diff --git a/binaries/aarch64/tpws b/binaries/aarch64/tpws index 5c828eb..9f1a42b 100755 Binary files a/binaries/aarch64/tpws and b/binaries/aarch64/tpws differ diff --git a/binaries/arm/tpws b/binaries/arm/tpws index 2e10ec7..b9276d7 100755 Binary files a/binaries/arm/tpws and b/binaries/arm/tpws differ diff --git a/binaries/freebsd-x64/tpws b/binaries/freebsd-x64/tpws index e64e742..cc7cafd 100755 Binary files a/binaries/freebsd-x64/tpws and b/binaries/freebsd-x64/tpws differ diff --git a/binaries/mac64/tpws b/binaries/mac64/tpws index 8302d6a..c769454 100755 Binary files a/binaries/mac64/tpws and b/binaries/mac64/tpws differ diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws index 560ac3d..af328c7 100755 Binary files a/binaries/mips32r1-lsb/tpws and b/binaries/mips32r1-lsb/tpws differ diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws index 3f0e801..25186dc 100755 Binary files a/binaries/mips32r1-msb/tpws and b/binaries/mips32r1-msb/tpws differ diff --git a/binaries/mips64r2-msb/tpws b/binaries/mips64r2-msb/tpws index 8a25225..adbf41c 100755 Binary files a/binaries/mips64r2-msb/tpws and b/binaries/mips64r2-msb/tpws differ diff --git a/binaries/ppc/tpws b/binaries/ppc/tpws index b328c17..0b17195 100755 Binary files a/binaries/ppc/tpws and b/binaries/ppc/tpws differ diff --git a/binaries/x86/tpws b/binaries/x86/tpws index c98e332..1aa921b 100755 Binary files a/binaries/x86/tpws and b/binaries/x86/tpws differ diff --git a/binaries/x86_64/tpws b/binaries/x86_64/tpws index 995751e..e71cbac 100755 Binary files a/binaries/x86_64/tpws and b/binaries/x86_64/tpws differ diff --git a/binaries/x86_64/tpws_wsl.tgz b/binaries/x86_64/tpws_wsl.tgz index 7a734d4..3058277 100644 Binary files a/binaries/x86_64/tpws_wsl.tgz and b/binaries/x86_64/tpws_wsl.tgz differ diff --git a/blockcheck.sh b/blockcheck.sh index 5243c55..a55cab0 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -645,6 +645,9 @@ tpws_check_domain_bypass() tpws_curl_test_update $1 $3 $s $s2 && break done done + for s2 in '--tlsrec=sni' '--tlsrec=sni --split-pos=10' '--tlsrec=sni --split-pos=10 --disorder'; do + tpws_curl_test_update $1 $3 $s2 && [ "$FORCE" != 1 ] && break + done fi report_strategy $1 $3 tpws } diff --git a/docs/LICENSE.txt b/docs/LICENSE.txt index 110c379..c906097 100644 --- a/docs/LICENSE.txt +++ b/docs/LICENSE.txt @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2016-2021 bol-van - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -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. +MIT License + +Copyright (c) 2016-2021 bol-van + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +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. diff --git a/docs/bsd.txt b/docs/bsd.txt index f09c85f..021513d 100644 --- a/docs/bsd.txt +++ b/docs/bsd.txt @@ -1,4 +1,4 @@ -Поддерживаемые версии +Поддерживаемые версии --------------------- FreeBSD 11.x+ , OpenBSD 6.x+, частично MacOS Sierra+ diff --git a/docs/bsdfw.txt b/docs/bsdfw.txt index 1d1970f..b1a7901 100644 --- a/docs/bsdfw.txt +++ b/docs/bsdfw.txt @@ -1,95 +1,95 @@ -WAN=em0 LAN=em1 - -FreeBSD IPFW : - -ipfw delete 100 -ipfw add 100 fwd 127.0.0.1,988 tcp from me to any 80,443 proto ip4 xmit em0 not uid daemon -ipfw add 100 fwd ::1,988 tcp from me to any 80,443 proto ip6 xmit em0 not uid daemon -ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 -ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 - -ipfw delete 100 -ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 -ipfw add 100 fwd 127.0.0.1,988 tcp from me to table\(zapret\) 80,443 proto ip4 xmit em0 not uid daemon -ipfw add 100 fwd ::1,988 tcp from me to table\(zapret\) 80,443 proto ip6 xmit em0 not uid daemon -ipfw add 100 allow tcp from any to table\(nozapret\) 80,443 recv em1 -ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 -ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 - -/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 - - -; Loop avoidance. -; FreeBSD artificially ignores sockarg for ipv6 in the kernel. -; This limitation is coming from the ipv6 early age. Code is still in "testing" state. 10-20 years. Everybody forgot about it. -; dvtws sends ipv6 forged frames using another divert socket (HACK). they can be filtered out using 'diverted'. - - -ipfw delete 100 -ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0 -ipfw add 100 divert 989 udp from any to any 443 out not diverted not sockarg xmit em0 - -ipfw delete 100 -ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 -ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted not sockarg xmit em0 - -/opt/zapret/nfq/dvtws --port=989 --debug --dpi-desync=split - - -sample ipfw NAT setup : - -WAN=em0 -LAN=em1 -ipfw -q flush -ipfw -q nat 1 config if $WAN unreg_only reset -ipfw -q add 10 allow ip from any to any via $LAN -ipfw -q add 20 allow ip from any to any via lo0 -ipfw -q add 300 nat 1 ip4 from any to any in recv $WAN -ipfw -q add 301 check-state -ipfw -q add 350 skipto 390 tcp from any to any out xmit $WAN setup keep-state -ipfw -q add 350 skipto 390 udp from any to any out xmit $WAN keep-state -ipfw -q add 360 allow all from any to me in recv $WAN -ipfw -q add 390 nat 1 ip4 from any to any out xmit $WAN -ipfw -q add 10000 allow ip from any to any - -Forwarding : -sysctl net.inet.ip.forwarding=1 -sysctl net.inet6.ip6.forwarding=1 - - -OpenBSD PF : - -; 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 - -; dvtws works both for routed and local - -pass in quick on em0 proto tcp from port {80,443} no state -pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state -pfctl -f /etc/pf.conf -./dvtws --port=989 --dpi-desync=split2 - -; dvtws with table limitations : to zapret,zapret6 but not to nozapret,nozapret6 -; reload tables : pfctl -f /etc/pf.conf -set limit table-entries 2000000 -table file "/opt/zapret/ipset/zapret-ip.txt" -table file "/opt/zapret/ipset/zapret-ip-user.txt" -table file "/opt/zapret/ipset/zapret-ip-exclude.txt" -pass out quick on em0 inet proto tcp to port {80,443} -pass in quick on em0 inet proto tcp from port {80,443} no state -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state -pass in quick on em0 inet proto tcp from port {80,443} no state -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state -table file "/opt/zapret/ipset/zapret-ip6.txt" -table file "/opt/zapret/ipset/zapret-ip-user6.txt" -table file "/opt/zapret/ipset/zapret-ip-exclude6.txt" -pass out quick on em0 inet6 proto tcp to port {80,443} -pass in quick on em0 inet6 proto tcp from port {80,443} no state -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state -pass in quick on em0 inet6 proto tcp from port {80,443} no state -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state +WAN=em0 LAN=em1 + +FreeBSD IPFW : + +ipfw delete 100 +ipfw add 100 fwd 127.0.0.1,988 tcp from me to any 80,443 proto ip4 xmit em0 not uid daemon +ipfw add 100 fwd ::1,988 tcp from me to any 80,443 proto ip6 xmit em0 not uid daemon +ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 +ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 + +ipfw delete 100 +ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 +ipfw add 100 fwd 127.0.0.1,988 tcp from me to table\(zapret\) 80,443 proto ip4 xmit em0 not uid daemon +ipfw add 100 fwd ::1,988 tcp from me to table\(zapret\) 80,443 proto ip6 xmit em0 not uid daemon +ipfw add 100 allow tcp from any to table\(nozapret\) 80,443 recv em1 +ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 +ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 + +/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 + + +; Loop avoidance. +; FreeBSD artificially ignores sockarg for ipv6 in the kernel. +; This limitation is coming from the ipv6 early age. Code is still in "testing" state. 10-20 years. Everybody forgot about it. +; dvtws sends ipv6 forged frames using another divert socket (HACK). they can be filtered out using 'diverted'. + + +ipfw delete 100 +ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0 +ipfw add 100 divert 989 udp from any to any 443 out not diverted not sockarg xmit em0 + +ipfw delete 100 +ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 +ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted not sockarg xmit em0 + +/opt/zapret/nfq/dvtws --port=989 --debug --dpi-desync=split + + +sample ipfw NAT setup : + +WAN=em0 +LAN=em1 +ipfw -q flush +ipfw -q nat 1 config if $WAN unreg_only reset +ipfw -q add 10 allow ip from any to any via $LAN +ipfw -q add 20 allow ip from any to any via lo0 +ipfw -q add 300 nat 1 ip4 from any to any in recv $WAN +ipfw -q add 301 check-state +ipfw -q add 350 skipto 390 tcp from any to any out xmit $WAN setup keep-state +ipfw -q add 350 skipto 390 udp from any to any out xmit $WAN keep-state +ipfw -q add 360 allow all from any to me in recv $WAN +ipfw -q add 390 nat 1 ip4 from any to any out xmit $WAN +ipfw -q add 10000 allow ip from any to any + +Forwarding : +sysctl net.inet.ip.forwarding=1 +sysctl net.inet6.ip6.forwarding=1 + + +OpenBSD PF : + +; 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 + +; dvtws works both for routed and local + +pass in quick on em0 proto tcp from port {80,443} no state +pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state +pfctl -f /etc/pf.conf +./dvtws --port=989 --dpi-desync=split2 + +; dvtws with table limitations : to zapret,zapret6 but not to nozapret,nozapret6 +; reload tables : pfctl -f /etc/pf.conf +set limit table-entries 2000000 +table file "/opt/zapret/ipset/zapret-ip.txt" +table file "/opt/zapret/ipset/zapret-ip-user.txt" +table file "/opt/zapret/ipset/zapret-ip-exclude.txt" +pass out quick on em0 inet proto tcp to port {80,443} +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state +table file "/opt/zapret/ipset/zapret-ip6.txt" +table file "/opt/zapret/ipset/zapret-ip-user6.txt" +table file "/opt/zapret/ipset/zapret-ip-exclude6.txt" +pass out quick on em0 inet6 proto tcp to port {80,443} +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state diff --git a/docs/changes.txt b/docs/changes.txt index 0a51dfe..f4e2504 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -1,245 +1,249 @@ -v1 - -Initial release - -v2 - -nfqws : command line options change. now using standard getopt. -nfqws : added options for window size changing and "Host:" case change -ISP support : tested on mns.ru and beeline (corbina) -init scripts : rewritten init scripts for simple choise of ISP -create_ipset : now using 'ipset restore', it works much faster -readme : updated. now using UTF-8 charset. - -v3 - -tpws : added transparent proxy (supports TPROXY and DNAT). - can help when ISP tracks whole HTTP session, not only the beginning -ipset : added zapret-hosts-user.txt which contain user defined host names to be resolved - and added to zapret ip list -ISP support : dom.ru support via TPROXY/DNAT -ISP support : successfully tested sknt.ru on 'domru' configuration - other configs will probably also work, but cannot test -compile : openwrt compile howto - -v4 - -tpws : added ability to insert extra space after http method : "GET /" => "GET /" -ISP support : TKT support - -v5 - -nfqws : ipv6 support in nfqws - -v6 - -ipset : added "get_antizapret.sh" - -v7 - -tpws : added ability to insert "." after Host: name - -v8 - -openwrt init : removed hotplug.d/firewall because of race conditions. now only use /etc/firewall.user - -v9 - -ipban : added ipban ipset. place domains banned by ip to zapret-hosts-user-ipban.txt - these IPs must be soxified for both http and https -ISP support : tiera support -ISP support : added DNS filtering to ubuntu and debian scripts - -v10 - -tpws : added split-pos option. split every message at specified position - -v11 - -ipset : scripts optimizations - -v12 - -nfqws : fix wrong tcp checksum calculation if packet length is odd and platform is big-endian - -v13 - -added binaries - -v14 - -change get_antizapret script to work with https://github.com/zapret-info/z-i/raw/master/dump.csv -filter out 192.168.*, 127.*, 10.* from blocked ips - -v15 - -added --hostspell option to nfqws and tpws -ISP support : beeline now catches "host" but other spellings still work -openwrt/LEDE : changed init script to work with procd -tpws, nfqws : minor cosmetic fixes - -v16 - -tpws: split-http-req=method : split inside method name, not after -ISP support : mns.ru changed split pos to 3 (got redirect page with HEAD req : curl -I ej.ru) - -v17 - -ISP support : athome moved from nfqws to tpws because of instability and http request hangs -tpws : added options unixeol,methodeol,hosttab - -v18 - -tpws,nfqws : added hostnospace option - -v19 - -tpws : added hostlist option - -v20 - -added ip2net. ip2net groups ips from iplist into subnets and reduces ipset size twice - -v21 - -added mdig. get_reestr.sh is *real* again - -v22 - -total review of init script logic -dropped support of older debian 7 and ubuntu 12/14 systems -install_bin.sh : auto binaries preparation -docs: readme review. some new topics added, others deleted -docs: VPN setup with policy based routing using wireguard -docs: wireguard modding guide - -v23 - -major init system rewrite -openwrt : separate firewall include /etc/firewall.zapret -install_easy.sh : easy setup on openwrt, debian, ubuntu, centos, fedora, opensuse - -v24 - -separate config from init scripts -gzip support in ipset/*.sh and tpws - -v25 - -init : move to native systemd units -use links to units, init scripts and firewall includes, no more copying - -v26 - -ipv6 support -tpws : advanced bind options - -v27 - -tpws : major connection code rewrite. originally it was derived from not top quality example , with many bugs and potential problems. -next generation connection code uses nonblocking sockets. now its in EXPERIMENTAL state. - -v28 - -tpws : added socks5 support -ipset : major RKN getlist rewrite. added antifilter.network support - -v29 - -nfqws : DPI desync attack -ip exclude system - -v30 - -nfqws : DPI desync attack modes : fake,rst - -v31 - -nfqws : DPI desync attack modes : disorder,disorder2,split,split2. -nfqws : DPI desync fooling mode : badseq. multiple modes supported - -v32 - -tpws : multiple binds -init scripts : run only one instance of tpws in any case - -v33 - -openwrt : flow offloading support -config : MODE refactoring - -v34 - -nfqws : dpi-desync 2 mode combos -nfqws : dpi-desync without parameter no more supported. previously it meant "fake" -nfqws : custom fake http request and tls client hello - -v35 - -limited FreeBSD and OpenBSD support - -v36 - -full FreeBSD and OpenBSD support - -v37 - -limited MacOS support - -v38 - -MacOS easy install - -v39 - -nfqws: conntrack, wssize - -v40 - -init scripts : IFACE_LAN, IFACE_WAN now accept multiple interfaces -init scripts : openwrt uses now OPENWRT_LAN parameter to override incoming interfaces for tpws - -v41 - -install_easy : openrc support - -v42 - -blockcheck.sh - -v43 - -nfqws: UDP desync with conntrack support (any-protocol only for now) - -v44 - -nfqws: ipfrag - -v45 - -nfqws: hop-by-hop ipv6 desync and fooling - -v46 - -big startup script refactoring to support nftables and new openwrt snapshot builds with firewall4 - -v47 - -nfqws: QUIC initial decryption -nfqws: udplen, fakeknown dpi desync modes - -v48 - -nfqws, tpws : multiple --hostlist and --hostlist-exclude support -launch system, ipset : no more list merging. all lists are passed separately to nfqws and tpws -nfqws : udplen fooling supports packet shrinking (negative increment value) - -v49 - -QUIC support integrated to the main system and setup - -v50 - -DHT protocol support. -DPI desync mode 'tamper' for DHT. -HEX string support in addition to binary files. +v1 + +Initial release + +v2 + +nfqws : command line options change. now using standard getopt. +nfqws : added options for window size changing and "Host:" case change +ISP support : tested on mns.ru and beeline (corbina) +init scripts : rewritten init scripts for simple choise of ISP +create_ipset : now using 'ipset restore', it works much faster +readme : updated. now using UTF-8 charset. + +v3 + +tpws : added transparent proxy (supports TPROXY and DNAT). + can help when ISP tracks whole HTTP session, not only the beginning +ipset : added zapret-hosts-user.txt which contain user defined host names to be resolved + and added to zapret ip list +ISP support : dom.ru support via TPROXY/DNAT +ISP support : successfully tested sknt.ru on 'domru' configuration + other configs will probably also work, but cannot test +compile : openwrt compile howto + +v4 + +tpws : added ability to insert extra space after http method : "GET /" => "GET /" +ISP support : TKT support + +v5 + +nfqws : ipv6 support in nfqws + +v6 + +ipset : added "get_antizapret.sh" + +v7 + +tpws : added ability to insert "." after Host: name + +v8 + +openwrt init : removed hotplug.d/firewall because of race conditions. now only use /etc/firewall.user + +v9 + +ipban : added ipban ipset. place domains banned by ip to zapret-hosts-user-ipban.txt + these IPs must be soxified for both http and https +ISP support : tiera support +ISP support : added DNS filtering to ubuntu and debian scripts + +v10 + +tpws : added split-pos option. split every message at specified position + +v11 + +ipset : scripts optimizations + +v12 + +nfqws : fix wrong tcp checksum calculation if packet length is odd and platform is big-endian + +v13 + +added binaries + +v14 + +change get_antizapret script to work with https://github.com/zapret-info/z-i/raw/master/dump.csv +filter out 192.168.*, 127.*, 10.* from blocked ips + +v15 + +added --hostspell option to nfqws and tpws +ISP support : beeline now catches "host" but other spellings still work +openwrt/LEDE : changed init script to work with procd +tpws, nfqws : minor cosmetic fixes + +v16 + +tpws: split-http-req=method : split inside method name, not after +ISP support : mns.ru changed split pos to 3 (got redirect page with HEAD req : curl -I ej.ru) + +v17 + +ISP support : athome moved from nfqws to tpws because of instability and http request hangs +tpws : added options unixeol,methodeol,hosttab + +v18 + +tpws,nfqws : added hostnospace option + +v19 + +tpws : added hostlist option + +v20 + +added ip2net. ip2net groups ips from iplist into subnets and reduces ipset size twice + +v21 + +added mdig. get_reestr.sh is *real* again + +v22 + +total review of init script logic +dropped support of older debian 7 and ubuntu 12/14 systems +install_bin.sh : auto binaries preparation +docs: readme review. some new topics added, others deleted +docs: VPN setup with policy based routing using wireguard +docs: wireguard modding guide + +v23 + +major init system rewrite +openwrt : separate firewall include /etc/firewall.zapret +install_easy.sh : easy setup on openwrt, debian, ubuntu, centos, fedora, opensuse + +v24 + +separate config from init scripts +gzip support in ipset/*.sh and tpws + +v25 + +init : move to native systemd units +use links to units, init scripts and firewall includes, no more copying + +v26 + +ipv6 support +tpws : advanced bind options + +v27 + +tpws : major connection code rewrite. originally it was derived from not top quality example , with many bugs and potential problems. +next generation connection code uses nonblocking sockets. now its in EXPERIMENTAL state. + +v28 + +tpws : added socks5 support +ipset : major RKN getlist rewrite. added antifilter.network support + +v29 + +nfqws : DPI desync attack +ip exclude system + +v30 + +nfqws : DPI desync attack modes : fake,rst + +v31 + +nfqws : DPI desync attack modes : disorder,disorder2,split,split2. +nfqws : DPI desync fooling mode : badseq. multiple modes supported + +v32 + +tpws : multiple binds +init scripts : run only one instance of tpws in any case + +v33 + +openwrt : flow offloading support +config : MODE refactoring + +v34 + +nfqws : dpi-desync 2 mode combos +nfqws : dpi-desync without parameter no more supported. previously it meant "fake" +nfqws : custom fake http request and tls client hello + +v35 + +limited FreeBSD and OpenBSD support + +v36 + +full FreeBSD and OpenBSD support + +v37 + +limited MacOS support + +v38 + +MacOS easy install + +v39 + +nfqws: conntrack, wssize + +v40 + +init scripts : IFACE_LAN, IFACE_WAN now accept multiple interfaces +init scripts : openwrt uses now OPENWRT_LAN parameter to override incoming interfaces for tpws + +v41 + +install_easy : openrc support + +v42 + +blockcheck.sh + +v43 + +nfqws: UDP desync with conntrack support (any-protocol only for now) + +v44 + +nfqws: ipfrag + +v45 + +nfqws: hop-by-hop ipv6 desync and fooling + +v46 + +big startup script refactoring to support nftables and new openwrt snapshot builds with firewall4 + +v47 + +nfqws: QUIC initial decryption +nfqws: udplen, fakeknown dpi desync modes + +v48 + +nfqws, tpws : multiple --hostlist and --hostlist-exclude support +launch system, ipset : no more list merging. all lists are passed separately to nfqws and tpws +nfqws : udplen fooling supports packet shrinking (negative increment value) + +v49 + +QUIC support integrated to the main system and setup + +v50 + +DHT protocol support. +DPI desync mode 'tamper' for DHT. +HEX string support in addition to binary files. + +v51 + +tpws --tlsrec attack. \ No newline at end of file diff --git a/docs/iptables.txt b/docs/iptables.txt index f00f3e2..fac4ca2 100644 --- a/docs/iptables.txt +++ b/docs/iptables.txt @@ -1,63 +1,63 @@ -For window size changing : - -iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -j NFQUEUE --queue-num 200 --queue-bypass -iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -m set --match-set zapret src -j NFQUEUE --queue-num 200 --queue-bypass - -For outgoing data manipulation ("Host:" case changing) : - -iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass -iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:5 -j NFQUEUE --queue-num 200 --queue-bypass - -For dpi desync attack : - -iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass -iptables -t mangle -I POSTROUTING -p tcp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass -iptables -t mangle -I POSTROUTING -p udp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass - - -For TPROXY : - -sysctl -w net.ipv4.ip_forward=1 -iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE - -ip -f inet rule add fwmark 1 lookup 100 -ip -f inet route add local default dev lo table 100 -# prevent loop -iptables -t filter -I INPUT -p tcp --dport 988 -j REJECT -iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j MARK --set-mark 1 -iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 988 - -iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -m set --match-set zapret dst -j MARK --set-mark 1 -iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -m mark --mark 0x1/0x1 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 988 - -For DNAT : - -# run tpws as user "tpws". its required to avoid loops. -sysctl -w net.ipv4.conf.eth1.route_localnet=1 -iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to 127.0.0.127:988 -iptables -t nat -I OUTPUT -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988 - - -Reset all iptable rules : - -iptables -F -iptables -X -iptables -t nat -F -iptables -t nat -X -iptables -t mangle -F -iptables -t mangle -X -iptables -t raw -F -iptables -t raw -X +For window size changing : + +iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -j NFQUEUE --queue-num 200 --queue-bypass +iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -m set --match-set zapret src -j NFQUEUE --queue-num 200 --queue-bypass + +For outgoing data manipulation ("Host:" case changing) : + +iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass +iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:5 -j NFQUEUE --queue-num 200 --queue-bypass + +For dpi desync attack : + +iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass +iptables -t mangle -I POSTROUTING -p tcp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass +iptables -t mangle -I POSTROUTING -p udp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass + + +For TPROXY : + +sysctl -w net.ipv4.ip_forward=1 +iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE + +ip -f inet rule add fwmark 1 lookup 100 +ip -f inet route add local default dev lo table 100 +# prevent loop +iptables -t filter -I INPUT -p tcp --dport 988 -j REJECT +iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j MARK --set-mark 1 +iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 988 + +iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -m set --match-set zapret dst -j MARK --set-mark 1 +iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -m mark --mark 0x1/0x1 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 988 + +For DNAT : + +# run tpws as user "tpws". its required to avoid loops. +sysctl -w net.ipv4.conf.eth1.route_localnet=1 +iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to 127.0.0.127:988 +iptables -t nat -I OUTPUT -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988 + + +Reset all iptable rules : + +iptables -F +iptables -X +iptables -t nat -F +iptables -t nat -X +iptables -t mangle -F +iptables -t mangle -X +iptables -t raw -F +iptables -t raw -X Reset iptable policies : -iptables -P INPUT ACCEPT -iptables -P FORWARD ACCEPT -iptables -P OUTPUT ACCEPT -iptables -t mangle -P POSTROUTING ACCEPT -iptables -t mangle -P PREROUTING ACCEPT -iptables -t mangle -P INPUT ACCEPT -iptables -t mangle -P FORWARD ACCEPT -iptables -t mangle -P OUTPUT ACCEPT -iptables -t raw -P PREROUTING ACCEPT -iptables -t raw -P OUTPUT ACCEPT +iptables -P INPUT ACCEPT +iptables -P FORWARD ACCEPT +iptables -P OUTPUT ACCEPT +iptables -t mangle -P POSTROUTING ACCEPT +iptables -t mangle -P PREROUTING ACCEPT +iptables -t mangle -P INPUT ACCEPT +iptables -t mangle -P FORWARD ACCEPT +iptables -t mangle -P OUTPUT ACCEPT +iptables -t raw -P PREROUTING ACCEPT +iptables -t raw -P OUTPUT ACCEPT diff --git a/docs/manual_setup.txt b/docs/manual_setup.txt index 4b7317e..ec8b47a 100644 --- a/docs/manual_setup.txt +++ b/docs/manual_setup.txt @@ -1,266 +1,266 @@ -Пример ручной установки на debian-подобную систему --------------------------------------------------- - -На debian основано большое количество дистрибутивов linux, включая ubuntu. -Здесь рассматриваются прежде всего Debian 8+ и Ubuntu 16+. -Но с большой вероятностью может сработать и на производных от них. -Главное условие - наличие systemd, apt и нескольких стандартных пакетов в репозитории. - -Установить пакеты : - apt-get update - apt-get install ipset curl dnsutils git - -Если хотите использовать nftables, то нужен пакет nftables, а ipset не обязателен. - -Скопировать директорию zapret в /opt или скачать через git : - cd /opt - git clone --depth 1 https://github.com/bol-van/zapret - -Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. - /opt/zapret/install_bin.sh -АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось. -Для сборки требуются dev пакеты : zlib1g-dev libcap-dev libnetfilter-queue-dev - -Настроить параметры согласно разделу "Выбор параметров". - -Создать ссылку на service unit в systemd : - ln -fs /opt/zapret/init.d/systemd/zapret.service /lib/systemd/system - -Удалить старые листы, если они были созданы ранее : - /opt/zapret/ipset/clear_lists.sh -По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. -Выполнить скрипт обновления листа : - /opt/zapret/ipset/get_config.sh -Настроить таймер systemd для обновления листа : - ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /lib/systemd/system - ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /lib/systemd/system - -Принять изменения в systemd : - systemctl daemon-reload - -Включить автозапуск службы : - systemctl enable zapret - -Включить таймер обновления листа : - systemctl enable zapret-list-update.timer - -Запустить службу : - systemctl start zapret - -Шпаргалка по управлению службой и таймером : - -enable auto start : systemctl enable zapret -disable auto start : systemctl disable zapret -start : systemctl start zapret -stop : systemctl stop zapret -status, output messages : systemctl status zapret -timer info : systemctl list-timer -delete service : systemctl disable zapret ; rm /lib/systemd/system/zapret.service -delete timer : systemctl disable zapret-list-update.timer ; rm /lib/systemd/system/zapret-list-update.* - -Centos 7+, Fedora ------------------ - -Centos с 7 версии и более-менее новые федоры построены на systemd. -В качестве пакетного менеджера используется yum. - -Установить пакеты : - yum install -y curl ipset dnsutils git - -Далее все аналогично debian. - -OpenSUSE --------- - -Новые OpenSUSE основаны на systemd и менеджере пакетов zypper. - -Установить пакеты : - zypper --non-interactive install curl ipset - -Далее все аналогично debian, кроме расположения systemd. -В opensuse он находится не в /lib/systemd, а в /usr/lib/systemd. -Правильные команды будут : - - ln -fs /opt/zapret/init.d/systemd/zapret.service /usr/lib/systemd/system - ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /usr/lib/systemd/system - ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /usr/lib/systemd/system - -Arch linux ----------- - -Построен на базе systemd. - -Установить пакеты : - pacman -Syy - pacman --noconfirm -S ipset curl - -Далее все аналогично debian. - -Gentoo ------- - -Эта система использует OpenRC - улучшенную версию sysvinit. -Установка пакетов производится командой : emerge -Пакеты собираются из исходников. - -Требуются все те же ipset, curl, git для скачивания с github. -git и curl по умолчанию могут присутствовать, ipset отсутствует. - - emerge ipset - -Настроить параметры согласно разделу "Выбор параметров". - -Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. - /opt/zapret/install_bin.sh -АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось. - -Удалить старые листы, если они были созданы ранее : - /opt/zapret/ipset/clear_lists.sh -По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. -Выполнить скрипт обновления листа : - /opt/zapret/ipset/get_config.sh -Зашедулить обновление листа : - crontab -e - Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh" - -Подключить init скрипт : - - ln -fs /opt/zapret/init.d/openrc/zapret /etc/init.d - rc-update add zapret - -Запустить службу : - - rc-service zapret start - -Шпаргалка по управлению службой : - -enable auto start : rc-update add zapret -disable auto start : rc-update del zapret -start : rc-service zapret start -stop : rc-service zapret stop - - - -Ручная установка на openwrt/LEDE 15.xx-21.xx --------------------------------------------- - -!!! Данная инструкция написана для систем, основанных на iptables+firewall3 -!!! В новых версиях openwrt переходит на nftables+firewall4, инструкция неприменима. Пользуйтесь install_easy.sh - -Установить дополнительные пакеты : -opkg update -opkg install iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra ipset curl -(ipv6) opkg install ip6tables-mod-nat -(опционально) opkg install gzip -(опционально) opkg install coreutils-sort - -ЭКОНОМИЯ МЕСТА : - -gzip от busybox в разы медленней полноценного варианта. gzip используется скриптами получения листов. -sort от busybox медленней полноценного варианта и жрет намного больше памяти. sort используется скриптами получения листов. -iptables-mod-nfqueue можно выкинуть, если не будем пользоваться nfqws -curl можно выкинуть, если для получения ip листа будет использоваться только get_user.sh - -Самая главная трудность - скомпилировать программы на C. Это можно сделать на linux x64 при помощи SDK, который -можно скачать с официального сайта openwrt или LEDE. Но процесс кросс компиляции - это всегда сложности. -Недостаточно запустить make как на традиционной linux системе. -Поэтому в binaries имеются готовые статические бинарики для всех самых распространенных архитектур. -Статическая сборка означает, что бинарик не зависит от типа libc (glibc, uclibc или musl) и наличия установленных so. -Его можно использовать сразу. Лишь бы подходил тип CPU. У ARM и MIPS есть несколько версий. -Скорее всего найдется рабочий вариант. Если нет - вам придется собирать самостоятельно. -Для всех поддерживаемых архитектур бинарики запакованы upx. На текущий момент все, кроме mips64. - -Скопировать директорию "zapret" в /opt на роутер. - -Если места достаточно, самый простой способ : - opkg update - opkg install git-http - mkdir /opt - cd /opt - git clone --depth 1 https://github.com/bol-van/zapret - -Если места немного : - opkg update - opkg install openssh-sftp-server unzip - ifconfig br-lan -Скачать на комп с github zip архив кнопкой "Clone or download"->Download ZIP -Скопировать средствами sftp zip архив на роутер в /tmp. - mkdir /opt - cd /opt - unzip /tmp/zapret-master.zip - mv zapret-master zapret - rm /tmp/zapret-master.zip - -Если места совсем мало : -На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов. -Запаковать в архив zapret.tar.gz. - nc -l -p 1111 1111 >zapret.tar.gz - -Не стоит работать с распакованной версией zapret на windows. Потеряются ссылки и chmod. - -Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. - /opt/zapret/install_bin.sh - -Создать ссылку на скрипт запуска : - ln -fs /opt/zapret/init.d/openwrt/zapret /etc/init.d -Создать ссылку на скрипт события поднятия интерфейса : - ln -fs /opt/zapret/init.d/openwrt/90-zapret /etc/hotplug.d/iface - -Настроить параметры согласно разделу "Выбор параметров". - -Удалить старые листы, если они были созданы ранее : - /opt/zapret/ipset/clear_lists.sh -По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. -Выполнить скрипт обновления листа : - /opt/zapret/ipset/get_config.sh -Зашедулить обновление листа : - crontab -e - Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh" - -Включить автозапуск службы и запустить ее : - /etc/init.d/zapret enable - /etc/init.d/zapret start -ПРИМЕЧАНИЕ : на этапе старта системы интерфейсы еще не подняты. в некоторых случаях невозможно правильно -сформировать параметры запуска демонов, не зная имя физического интерфейса LAN. -Cкрипт из /etc/hotplug.d/iface перезапустит демоны по событию поднятия LAN. - -Создать ссылку на firewall include : - ln -fs /opt/zapret/init.d/openwrt/firewall.zapret /etc/firewall.zapret -Проверить была ли создана ранее запись о firewall include : - uci show firewall | grep firewall.zapret -Если firewall.zapret нет, значит добавить : - uci add firewall include - uci set firewall.@include[-1].path="/etc/firewall.zapret" - uci set firewall.@include[-1].reload="1" - uci commit firewall -Проверить не включен ли flow offload : - uci show firewall.@defaults[0] -Если flow_offloading=1 или flow_offloading_hw=1 , - uci set firewall.@defaults[0].flow_offloading=0 - uci set firewall.@defaults[0].flow_offloading_hw=0 - uci commit firewall -Перезапустить фаервол : - fw3 restart - -Посмотреть через iptables -nL, ip6tables -nL или через luci вкладку "firewall" появились ли нужные правила. - -ЭКОНОМИЯ МЕСТА : если его мало, то можно оставить в директории zapret лишь подкаталоги -ipset, common, файл config, init.d/openwrt. -Далее нужно создать подкаталоги с реально используемыми бинариками (ip2net, mdig, tpws, nfq) -и скопировать туда из binaries рабочие executables. - -ЕСЛИ ВСЕ ПЛОХО С МЕСТОМ : откажитесь от работы со списком РКН. используйте только get_user.sh - -ЕСЛИ СОВСЕМ ВСЕ УЖАСНО С МЕСТОМ : берете tpws и делаете все своими руками. поднятие iptables, автостарт бинарика. -С некоторых версий скрипты запуска zapret без ipset не работают (он требуется для ip exclude) - -СОВЕТ : Покупайте только роутеры с USB. В USB можно воткнуть флэшку и вынести на нее корневую файловую систему -или использовать ее в качестве оверлея. Не надо мучать себя, запихивая незапихиваемое в 8 мб встроенной флэшки. -Для комфортной работы с zapret нужен роутер с 16 Mb встроенной памяти или USB разъемом и 128+ Mb RAM. -На 64 Mb без swap будут проблемы с листами РКН. Если у вас только 64 Mb, и вы хотите листы РКН, подключите swap. -32 Mb для современных версий openwrt - конфигурация на грани живучести. Возможны хаотические падения процессов в oom. -Работа с листами РКН невозможна в принципе. - +Пример ручной установки на debian-подобную систему +-------------------------------------------------- + +На debian основано большое количество дистрибутивов linux, включая ubuntu. +Здесь рассматриваются прежде всего Debian 8+ и Ubuntu 16+. +Но с большой вероятностью может сработать и на производных от них. +Главное условие - наличие systemd, apt и нескольких стандартных пакетов в репозитории. + +Установить пакеты : + apt-get update + apt-get install ipset curl dnsutils git + +Если хотите использовать nftables, то нужен пакет nftables, а ipset не обязателен. + +Скопировать директорию zapret в /opt или скачать через git : + cd /opt + git clone --depth 1 https://github.com/bol-van/zapret + +Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. + /opt/zapret/install_bin.sh +АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось. +Для сборки требуются dev пакеты : zlib1g-dev libcap-dev libnetfilter-queue-dev + +Настроить параметры согласно разделу "Выбор параметров". + +Создать ссылку на service unit в systemd : + ln -fs /opt/zapret/init.d/systemd/zapret.service /lib/systemd/system + +Удалить старые листы, если они были созданы ранее : + /opt/zapret/ipset/clear_lists.sh +По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. +Выполнить скрипт обновления листа : + /opt/zapret/ipset/get_config.sh +Настроить таймер systemd для обновления листа : + ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /lib/systemd/system + ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /lib/systemd/system + +Принять изменения в systemd : + systemctl daemon-reload + +Включить автозапуск службы : + systemctl enable zapret + +Включить таймер обновления листа : + systemctl enable zapret-list-update.timer + +Запустить службу : + systemctl start zapret + +Шпаргалка по управлению службой и таймером : + +enable auto start : systemctl enable zapret +disable auto start : systemctl disable zapret +start : systemctl start zapret +stop : systemctl stop zapret +status, output messages : systemctl status zapret +timer info : systemctl list-timer +delete service : systemctl disable zapret ; rm /lib/systemd/system/zapret.service +delete timer : systemctl disable zapret-list-update.timer ; rm /lib/systemd/system/zapret-list-update.* + +Centos 7+, Fedora +----------------- + +Centos с 7 версии и более-менее новые федоры построены на systemd. +В качестве пакетного менеджера используется yum. + +Установить пакеты : + yum install -y curl ipset dnsutils git + +Далее все аналогично debian. + +OpenSUSE +-------- + +Новые OpenSUSE основаны на systemd и менеджере пакетов zypper. + +Установить пакеты : + zypper --non-interactive install curl ipset + +Далее все аналогично debian, кроме расположения systemd. +В opensuse он находится не в /lib/systemd, а в /usr/lib/systemd. +Правильные команды будут : + + ln -fs /opt/zapret/init.d/systemd/zapret.service /usr/lib/systemd/system + ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /usr/lib/systemd/system + ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /usr/lib/systemd/system + +Arch linux +---------- + +Построен на базе systemd. + +Установить пакеты : + pacman -Syy + pacman --noconfirm -S ipset curl + +Далее все аналогично debian. + +Gentoo +------ + +Эта система использует OpenRC - улучшенную версию sysvinit. +Установка пакетов производится командой : emerge +Пакеты собираются из исходников. + +Требуются все те же ipset, curl, git для скачивания с github. +git и curl по умолчанию могут присутствовать, ipset отсутствует. + + emerge ipset + +Настроить параметры согласно разделу "Выбор параметров". + +Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. + /opt/zapret/install_bin.sh +АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось. + +Удалить старые листы, если они были созданы ранее : + /opt/zapret/ipset/clear_lists.sh +По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. +Выполнить скрипт обновления листа : + /opt/zapret/ipset/get_config.sh +Зашедулить обновление листа : + crontab -e + Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh" + +Подключить init скрипт : + + ln -fs /opt/zapret/init.d/openrc/zapret /etc/init.d + rc-update add zapret + +Запустить службу : + + rc-service zapret start + +Шпаргалка по управлению службой : + +enable auto start : rc-update add zapret +disable auto start : rc-update del zapret +start : rc-service zapret start +stop : rc-service zapret stop + + + +Ручная установка на openwrt/LEDE 15.xx-21.xx +-------------------------------------------- + +!!! Данная инструкция написана для систем, основанных на iptables+firewall3 +!!! В новых версиях openwrt переходит на nftables+firewall4, инструкция неприменима. Пользуйтесь install_easy.sh + +Установить дополнительные пакеты : +opkg update +opkg install iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra ipset curl +(ipv6) opkg install ip6tables-mod-nat +(опционально) opkg install gzip +(опционально) opkg install coreutils-sort + +ЭКОНОМИЯ МЕСТА : + +gzip от busybox в разы медленней полноценного варианта. gzip используется скриптами получения листов. +sort от busybox медленней полноценного варианта и жрет намного больше памяти. sort используется скриптами получения листов. +iptables-mod-nfqueue можно выкинуть, если не будем пользоваться nfqws +curl можно выкинуть, если для получения ip листа будет использоваться только get_user.sh + +Самая главная трудность - скомпилировать программы на C. Это можно сделать на linux x64 при помощи SDK, который +можно скачать с официального сайта openwrt или LEDE. Но процесс кросс компиляции - это всегда сложности. +Недостаточно запустить make как на традиционной linux системе. +Поэтому в binaries имеются готовые статические бинарики для всех самых распространенных архитектур. +Статическая сборка означает, что бинарик не зависит от типа libc (glibc, uclibc или musl) и наличия установленных so. +Его можно использовать сразу. Лишь бы подходил тип CPU. У ARM и MIPS есть несколько версий. +Скорее всего найдется рабочий вариант. Если нет - вам придется собирать самостоятельно. +Для всех поддерживаемых архитектур бинарики запакованы upx. На текущий момент все, кроме mips64. + +Скопировать директорию "zapret" в /opt на роутер. + +Если места достаточно, самый простой способ : + opkg update + opkg install git-http + mkdir /opt + cd /opt + git clone --depth 1 https://github.com/bol-van/zapret + +Если места немного : + opkg update + opkg install openssh-sftp-server unzip + ifconfig br-lan +Скачать на комп с github zip архив кнопкой "Clone or download"->Download ZIP +Скопировать средствами sftp zip архив на роутер в /tmp. + mkdir /opt + cd /opt + unzip /tmp/zapret-master.zip + mv zapret-master zapret + rm /tmp/zapret-master.zip + +Если места совсем мало : +На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов. +Запаковать в архив zapret.tar.gz. + nc -l -p 1111 1111 >zapret.tar.gz + +Не стоит работать с распакованной версией zapret на windows. Потеряются ссылки и chmod. + +Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. + /opt/zapret/install_bin.sh + +Создать ссылку на скрипт запуска : + ln -fs /opt/zapret/init.d/openwrt/zapret /etc/init.d +Создать ссылку на скрипт события поднятия интерфейса : + ln -fs /opt/zapret/init.d/openwrt/90-zapret /etc/hotplug.d/iface + +Настроить параметры согласно разделу "Выбор параметров". + +Удалить старые листы, если они были созданы ранее : + /opt/zapret/ipset/clear_lists.sh +По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. +Выполнить скрипт обновления листа : + /opt/zapret/ipset/get_config.sh +Зашедулить обновление листа : + crontab -e + Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh" + +Включить автозапуск службы и запустить ее : + /etc/init.d/zapret enable + /etc/init.d/zapret start +ПРИМЕЧАНИЕ : на этапе старта системы интерфейсы еще не подняты. в некоторых случаях невозможно правильно +сформировать параметры запуска демонов, не зная имя физического интерфейса LAN. +Cкрипт из /etc/hotplug.d/iface перезапустит демоны по событию поднятия LAN. + +Создать ссылку на firewall include : + ln -fs /opt/zapret/init.d/openwrt/firewall.zapret /etc/firewall.zapret +Проверить была ли создана ранее запись о firewall include : + uci show firewall | grep firewall.zapret +Если firewall.zapret нет, значит добавить : + uci add firewall include + uci set firewall.@include[-1].path="/etc/firewall.zapret" + uci set firewall.@include[-1].reload="1" + uci commit firewall +Проверить не включен ли flow offload : + uci show firewall.@defaults[0] +Если flow_offloading=1 или flow_offloading_hw=1 , + uci set firewall.@defaults[0].flow_offloading=0 + uci set firewall.@defaults[0].flow_offloading_hw=0 + uci commit firewall +Перезапустить фаервол : + fw3 restart + +Посмотреть через iptables -nL, ip6tables -nL или через luci вкладку "firewall" появились ли нужные правила. + +ЭКОНОМИЯ МЕСТА : если его мало, то можно оставить в директории zapret лишь подкаталоги +ipset, common, файл config, init.d/openwrt. +Далее нужно создать подкаталоги с реально используемыми бинариками (ip2net, mdig, tpws, nfq) +и скопировать туда из binaries рабочие executables. + +ЕСЛИ ВСЕ ПЛОХО С МЕСТОМ : откажитесь от работы со списком РКН. используйте только get_user.sh + +ЕСЛИ СОВСЕМ ВСЕ УЖАСНО С МЕСТОМ : берете tpws и делаете все своими руками. поднятие iptables, автостарт бинарика. +С некоторых версий скрипты запуска zapret без ipset не работают (он требуется для ip exclude) + +СОВЕТ : Покупайте только роутеры с USB. В USB можно воткнуть флэшку и вынести на нее корневую файловую систему +или использовать ее в качестве оверлея. Не надо мучать себя, запихивая незапихиваемое в 8 мб встроенной флэшки. +Для комфортной работы с zapret нужен роутер с 16 Mb встроенной памяти или USB разъемом и 128+ Mb RAM. +На 64 Mb без swap будут проблемы с листами РКН. Если у вас только 64 Mb, и вы хотите листы РКН, подключите swap. +32 Mb для современных версий openwrt - конфигурация на грани живучести. Возможны хаотические падения процессов в oom. +Работа с листами РКН невозможна в принципе. + diff --git a/docs/nftables.txt b/docs/nftables.txt index b342287..6fb387a 100644 --- a/docs/nftables.txt +++ b/docs/nftables.txt @@ -1,26 +1,26 @@ -nftables test cheat sheet -simplified rules to test nfqws and tpws - - -For DNAT : - -# run tpws as user "tpws". its required to avoid loops. - -nft delete table inet ztest -nft create table inet ztest -nft add chain inet ztest pre "{type nat hook prerouting priority dstnat;}" -nft add rule inet ztest pre tcp dport "{80,443}" redirect to :988 -nft add chain inet ztest out "{type nat hook output priority -100;}" -nft add rule inet ztest out tcp dport "{80,443}" skuid != tpws redirect to :988 - - -For dpi desync attack : - -nft delete table inet ztest -nft create table inet ztest -nft add chain inet ztest post "{type filter hook postrouting priority mangle;}" -nft add rule inet ztest post tcp dport "{80,443}" queue num 200 bypass - - -show rules : nft list table inet ztest -delete table : nft delete table inet ztest +nftables test cheat sheet +simplified rules to test nfqws and tpws + + +For DNAT : + +# run tpws as user "tpws". its required to avoid loops. + +nft delete table inet ztest +nft create table inet ztest +nft add chain inet ztest pre "{type nat hook prerouting priority dstnat;}" +nft add rule inet ztest pre tcp dport "{80,443}" redirect to :988 +nft add chain inet ztest out "{type nat hook output priority -100;}" +nft add rule inet ztest out tcp dport "{80,443}" skuid != tpws redirect to :988 + + +For dpi desync attack : + +nft delete table inet ztest +nft create table inet ztest +nft add chain inet ztest post "{type filter hook postrouting priority mangle;}" +nft add rule inet ztest post tcp dport "{80,443}" queue num 200 bypass + + +show rules : nft list table inet ztest +delete table : nft delete table inet ztest diff --git a/docs/nftables_notes.txt b/docs/nftables_notes.txt index 45fd258..33b26b8 100644 --- a/docs/nftables_notes.txt +++ b/docs/nftables_notes.txt @@ -1,4 +1,4 @@ -nftables - это технология, пришедшая на замену iptables. +nftables - это технология, пришедшая на замену iptables. В ней собрали все, что относилось к различным iptables. А их немало. iptables, ip6tables, ebtables, arptables, ipset. Весь код из разрозненных, но похожих компонент, собрали в одно целое с единым синтаксисом. Добавили различные конструкции языка, позволяющие писать правила более лаконично, не повторяя одни и те же команды с небольшими различиями. diff --git a/docs/quick_start.txt b/docs/quick_start.txt index a16ae4b..9259a86 100644 --- a/docs/quick_start.txt +++ b/docs/quick_start.txt @@ -1,4 +1,4 @@ -Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt. +Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt. Предупреждение : не пишите в issue вопросы типа "как скопировать файл", "как скачать", "как запустить", ... То есть все , что касается базовых навыков обращения с ОС linux. Эти вопросы буду закрывать сразу. diff --git a/docs/readme.eng.md b/docs/readme.eng.md index d93d42a..ac1c51f 100644 --- a/docs/readme.eng.md +++ b/docs/readme.eng.md @@ -1,1288 +1,1076 @@ -## Table of contents - -- [Table of contents](#table-of-contents) -- [What is it for](#what-is-it-for) -- [How it works](#how-it-works) -- [How to put this into practice in the Linux system](#how-to-put-this-into-practice-in-the-linux-system) -- [ip6tables](#ip6tables) -- [nftables](#nftables) -- [When it will not work](#when-it-will-not-work) -- [`nfqws`](#nfqws) - - [DPI desync attack](#dpi-desync-attack) - - [DPI desync combos](#dpi-desync-combos) - - [SYNACK mode](#synack-mode) - - [Virtual Machines](#virtual-machines) - - [CONNTRACK](#conntrack) - - [UDP support](#udp-support) - - [IP fragmentation](#ip-fragmentation) -- [`tpws`](#tpws) -- [Ways to get a list of blocked IP](#ways-to-get-a-list-of-blocked-ip) -- [Domain name filtering](#domain-name-filtering) -- [Choosing parameters](#choosing-parameters) -- [Screwing to the firewall control system or your launch system](#screwing-to-the-firewall-control-system-or-your-launch-system) -- [Installation](#installation) - - [Checking ISP](#checking-isp) - - [Desktop Linux system](#desktop-linux-system) - - [OpenWRT](#openwrt) - - [Android](#android) - - [FreeBSD, OpenBSD, MacOS](#freebsd-openbsd-macos) - - [Windows (WSL)](#windows-wsl) - - [Other devices](#other-devices) - -## What is it for - -A stand-alone (without 3rd party servers) DPI circumvention tool. May allow to -bypass HTTP[S] website blocking or speed shaping, resist signature tcp/udp -protocol discovery. - -The project is mainly aimed at the Russian audience to fight russian regulator -named "Roskomnadzor". Some features of the project are russian reality specific -(such as getting list of sites blocked by Roskomnadzor), but most others are -common. - -Mainly OpenWRT targeted but also supports traditional Linux, FreeBSD, OpenBSD, -partially MacOS. - - -## How it works - -In the simplest case you are dealing with passive DPI. Passive DPI can read -passthrough traffic, inject its own packets, but cannot drop packets. - -If the request is prohibited the passive DPI will inject its own RST packet and -optionally HTTP redirect packet. - -If fake packets from DPI are only sent to client, you can use iptables commands -to drop them if you can write correct filter rules. This requires manual -in-deep traffic analysis and tuning for specific ISP. - -This is how we bypass the consequences of a ban trigger. - -If the passive DPI sends an RST packet also to the server, there is nothing you -can do about it. Your task is to prevent ban trigger from firing up. Iptables -alone will not work. This project is aimed at preventing the ban rather than -eliminating its consequences. - -To do that send what DPI does not expect and what breaks its algorithm of -recognizing requests and blocking them. - -Some DPIs cannot recognize the HTTP request if it is divided into TCP segments. - -For example, a request of the form `GET / HTTP / 1.1\r\nHost: kinozal.tv ...` -gets sent as 2 parts: first `GET`, then -`/ HTTP / 1.1 \r\nHost: kinozal.tv ...`. - -Other DPIs stumble when the `Host:` header is written in another case: for -example, `host:`. - -Sometimes work adding extra space after the method: `GET /` => `GET /` or -adding a dot at the end of the host name: `Host: kinozal.tv.` - -There is also more advanced magic for bypassing DPI at the packet level. - - -## How to put this into practice in the Linux system - -In short, the options can be classified according to the following scheme: - -1. Passive DPI not sending RST to the server. ISP tuned iptables commands can - help. This option is out of the scope of the project. If you do not allow - ban trigger to fire, then you won’t have to deal with its consequences. - -2. Modification of the TCP connection at the stream level. Implemented through - a proxy or transparent proxy. - -3. Modification of TCP connection at the packet level. Implemented through the - NFQUEUE handler and raw sockets. - -For options 2 and 3, tpws and nfqws programs are implemented, respectively. You -need to run them with the necessary parameters and redirect certain traffic -with iptables or nftables. - -To redirect a TCP connection to a transparent proxy, the following commands are -used: - -Forwarded traffic: -``` -iptables -t nat -I PREROUTING -i -p -tcp --dport 80 -j DNAT --to 127.0.0.127:988 -``` - -Outgoing traffic: -``` -iptables -t nat -I OUTPUT -o -p tcp ---dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988 -``` - -DNAT on localhost works in the OUTPUT chain, but does not work in the -PREROUTING chain without enabling the route_localnet parameter: -``` -sysctl -w net.ipv4.conf..route_localnet=1 -``` - -You can use `-j REDIRECT --to-port 988` instead of DNAT, but in this case the -transparent proxy process should listen on the ip address of the incoming -interface or on all addresses. Listen all - not good in terms of security. -Listening one (local) is possible, but automated scripts will have to recognize -it, then dynamically enter it into the command. In any case, additional efforts -are required. Using route_localnet can also introduce some security risks. You -make available from internal_interface everything bound to `127.0.0.0/8`. -Services are usually bound to `127.0.0.1`. - -Its possible to deny input to `127.0.0.1` from all interfaces except lo or bind -tpws to any other IP from `127.0.0.0/8` range, for example to `127.0.0.127`, -and allow incomings only to that IP: -``` -iptables -A INPUT ! -i lo -d 127.0.0.127 -j ACCEPT -iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j DROP -``` - -Owner filter is necessary to prevent recursive redirection of connections from -tpws itself. tpws must be started under OS user `tpws`. - -NFQUEUE redirection of the outgoing traffic and forwarded traffic going towards -the external interface, can be done with the following commands: -``` -iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -j -NFQUEUE --queue-num 200 --queue-bypass -``` - -In order not to touch the traffic to unblocked addresses, you can take a list -of blocked hosts, resolve it into IP addresses and put them to `ipset` 'zapret', -then add a filter to the command: -``` -iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -m -set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass -``` - -Some DPIs catch only the first HTTP request, ignoring subsequent requests in a -keep-alive session. Then we can reduce CPU load, refusing to process -unnecessary packets: -``` -iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -m -connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m -mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE ---queue-num 200 --queue-bypass -``` - -Mark filter does not allow nfqws-generated packets to enter the queue again. -Its necessary to use this filter when also using `connbytes 1:4`. Without it -packet ordering can be changed breaking the whole idea. - -## ip6tables - -ip6tables work almost exactly the same way as ipv4, but there are a number of -important nuances. In DNAT, you should take the address `--to` in square -brackets. For example: -``` -ip6tables -t nat -I OUTPUT -o -p tcp --dport 80 -m owner -! --uid-owner tpws -j DNAT --to [::1]:988 -``` - -The route_localnet parameter does not exist for ipv6. DNAT to localhost (`::1`) -is possible only in the OUTPUT chain. In the PREROUTING DNAT chain, it is -possible to any global address or to the link local address of the same -interface the packet came from. NFQUEUE works without changes. - -## nftables - -nftables are fine except one very big problem. nft requires tons of RAM to load -large nf sets (ip lists) with subnets/intervals. Most of the home routers can't -afford that. For example, even a 256 Mb system can't load a 100K ip list. nft -process will OOM. nf sets do not support overlapping intervals and that's why -nft process applies very RAM consuming algorithm to merge intervals so they -don't overlap. There're equivalents to iptables for all other functions. -Interface and protocol anonymous sets allow not to write multiple similar -rules. Flow offloading is built-in into new Linux kernels and nft versions. - -nft version `1.0.2` or higher is recommended. - - -## When it will not work - -* If DNS server returns false responses. ISP can return false IP addresses or - not return anything when blocked domains are queried. If this is the case - change DNS to public ones, such as `8.8.8.8` or `1.1.1.1`. Sometimes ISP hijacks - queries to any DNS server. Dnscrypt or dns-over-tls help. - -* If blocking is done by IP. - -* If a connection passes through a filter capable of reconstructing a TCP - connection, and which follows all standards. For example, we are routed to - squid. Connection goes through the full OS tcpip stack, fragmentation - disappears immediately as a means of circumvention. Squid is correct, it will - find everything as it should, it is useless to deceive him. BUT. Only small - providers can afford using squid, since it is very resource intensive. Large - companies usually use DPI, which is designed for much greater bandwidth. - - -## `nfqws` - -This program is a packet modifier and a NFQUEUE queue handler. For BSD systems -there is `dvtws` (See [BSD documentation](./bsd.eng.md)). Its built from the -same source and has almost the same parameters. - -`nfqws` takes the following parameters: -``` ---debug=0|1 ---qnum= ---daemon ; Daemonize ---pidfile= ; Write pid to file ---user= ; Drop root privs ---uid=uid[:gid] ; 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=[:] ; Set window size. 0 = do not modify. OBSOLETE ! ---wssize=[:] ; 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 ---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 ---dpi-desync=[,][,] ; Try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper ---dpi-desync-fwmark= ; Override fwmark for desync packet. default = 0x40000000 (1073741824) ---dpi-desync-ttl= ; Set ttl for desync packet ---dpi-desync-ttl6= ; Set ipv6 hop limit for desync packet. by default ttl value is used. ---dpi-desync-fooling=[,] ; Can use multiple comma separated values. modes : none md5sig ts badseq badsum hopbyhop hopbyhop2 ---dpi-desync-retrans=0|1 ; 0(default)=reinject original data packet after fake 1=drop original data packet to force its retransmission ---dpi-desync-repeats= ; 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=<1..9216> ; Data payload split position ---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= ; Badseq fooling seq signed increment. default -10000 ---dpi-desync-badack-increment= ; 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=|0xHEX ; File containing fake http request ---dpi-desync-fake-tls=|0xHEX ; File containing fake TLS ClientHello (for https) ---dpi-desync-fake-unknown=|0xHEX ; File containing unknown protocol fake payload ---dpi-desync-fake-quic=|0xHEX ; File containing fake QUIC Initial ---dpi-desync-fake-wireguard=|0xHEX ; File containing fake wireguard handshake initiation ---dpi-desync-fake-dht=|0xHEX ; File containing fake DHT (d1..e) ---dpi-desync-fake-unknown-udp=|0xHEX ; File containing unknown udp protocol fake payload ---dpi-desync-udplen-increment= ; Increase or decrease udp packet length by N bytes (default 2). negative values decrease length. ---dpi-desync-udplen-pattern=|0xHEX ; Udp tail fill pattern ---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= ; Apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) ---hostlist-exclude= ; Do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) -``` - -The manipulation parameters can be combined in any way. - -**WARNING**: -`--wsize` parameter is now not used anymore in scripts. TCP split can -be achieved using DPI desync attack. - -### DPI desync attack - -After completion of the tcp 3-way handshake, the first data packet from the -client goes. It usually has `GET / ...` or TLS ClientHello. We drop this -packet, replacing with something else. It can be a fake version with another -harmless but valid HTTP or HTTPS request (`fake`), tcp reset packet -(`rst`,`rstack`), split into 2 segments original packet with fake segment in -the middle (`split`). `fakeknown` sends fake only in response to known -application protocol. - -In articles these attack have names *TCB desynchronization* and *TCB teardown*. -Fake packet must reach DPI, but do not reach the destination server. - -The following means are available: set a low TTL, send a packet with bad -checksum, add tcp option **MD5 signature**. All of them have their own -disadvantages: - -* `md5sig` does not work on all servers - -* `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 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. In openwrt mentioned sysctl is set to 0 from the - box, in other routers its often left in the default "1" state. For `nfqws` to - work properly through the router set `net.netfilter.nf_conntrack_checksum=0` - on the router. System never verifies checksums of locally generated packets - so nfqws will always work on the router itself. If you are behind another - NAT, such as a ISP, and it does not pass invalid packages, there is nothing - you can do about it. But usually ISPs pass badsum. Some - adapters/switches/drivers enable hardware filtering of rx badsum not allowing - it to pass to the OS. This behavior was observed on a Mediatek MT7621 based - device. Tried to modify mediatek ethernet driver with no luck, likely - hardware enforced limitation. However the device allowed to send badsum - packets, problem only existed for passthrough traffic from clients. - -* `badseq` packets will be dropped by server, but DPI also can ignore them. - default badseq increment is set to -10000 because some DPIs drop packets - outside of the small tcp window. But this also can cause troubles when - `--dpi-desync-any-protocol` is enabled. To be 100% sure fake packet cannot - fit to server tcp window consider setting badseq increment to 0x80000000 - -* TTL looks like the best option, but it requires special tuning for each ISP. - If DPI is further than local ISP websites you can cut access to them. Manual - IP exclude list is required. Its possible to use md5sig with ttl. This way - you cant hurt anything, but good chances it will help to open local ISP - websites. If automatic solution cannot be found then use - `zapret-hosts-user-exclude.txt`. Some router stock firmwares fix outgoing - TTL. Without switching this option off TTL fooling will not work. - -* `hopbyhop` is ipv6 only. This fooling adds empty extension header `hop-by-hop - options` or two headers in case of `hopbyhop2`. Packets with two hop-by-hop - headers violate RFC and discarded by all operating systems. All OS accept - packets with one hop-by-hop header. Some ISPs/operators drop ipv6 packets - with hop-by-hop options. Fakes will not be processed by the server either - because ISP drops them or because there are two same headers. DPIs may still - anaylize packets with one or two hop-by-hop headers. - -`--dpi-desync-fooling` takes multiple comma separated values. - -For `fake`,`rst`,`rstack` modes original packet can be sent after the fake one or -just dropped. If its dropped OS will perform first retransmission after 0.2 -sec, then the delay increases exponentially. Delay can help to make sure fake -and original packets are properly ordered and processed on DPI. When -`dpi-desync-retrans=1` its mandatory to use connbytes in iptables rule. -Otherwise loop happens. - -Disorder mode splits original packet and sends packets in the following order: -1. 2nd segment -2. Fake 1st segment, data filled with zeroes -3. 1st segment -4. Fake 1st segment, data filled with zeroes (2nd copy) - -Original packet is always dropped. `--dpi-desync-split-pos` sets split position -(default 2). If position is higher than packet length, pos=1 is used. This -sequence is designed to make reconstruction of critical message as difficult as -possible. Fake segments may not be required to bypass some DPIs, but can -potentially help if more sophisticated reconstruction algorithms are used. Mode -`disorder2` disables sending of fake segments. - -Split mode is very similar to disorder but without segment reordering: -1. Fake 1st segment, data filled with zeroes -2. 1st segment -3. Fake 1st segment, data filled with zeroes (2nd copy) -4. 2nd segment - -Mode `split2` disables sending of fake segments. It can be used as a faster -alternative to `--wsize`. - -In `disorder2` and `split2` modes no fake packets are sent, so ttl and fooling -options are not required. - -`hopbyhop`, `destopt` and `ipfrag1` desync modes (they're not the same as -`hopbyhop` fooling!) are ipv6 only. - -One `hop-by-hop`, `destination options` or `fragment` header is added to all -desynced packets. Extra header increases packet size and can't be applied to -the maximum size packets. If it's not possible to send modified packet original -one will be sent. The idea here is that DPI sees 0 in the next header field of -the main ipv6 header and does not walk through the extension header chain until -transport header is found. - -`hopbyhop`, `destopt`, `ipfrag1` modes can be used with any second phase mode -except `ipfrag1+ipfrag2`. For example, `hopbyhop,split2` means split original -tcp packet into 2 pieces and add hop-by-hop header to both. With -`hopbyhop,ipfrag2` header sequence will be: `ipv6,hop-by-hop,fragment,tcp/udp`. - -`ipfrag1` mode may not always work without special preparations. See "IP -Fragmentation" notices. - -There are DPIs that analyze responses from the server, particularly the -certificate from the ServerHello that contain domain name(s). The ClientHello -delivery confirmation is an ACK packet from the server with ACK sequence number -corresponding to the length of the ClientHello+1. - -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). 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. - -Hosts are extracted from plain HTTP request `Host` header and SNI of -ClientHello TLS message. Subdomains are applied automatically. gzip lists are -supported. - -`iptables` for performing the attack on the first packet: -``` -iptables -t mangle -I POSTROUTING -o -p tcp -m multiport ---dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets ---connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num -200 --queue-bypass -``` - -This is good if DPI does not track all requests in HTTP keep-alive session. If -it does, then pass all outgoing packets for HTTP and only first data packet for -HTTPS: -``` -iptables -t mangle -I POSTROUTING -o -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass -iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass -``` - -Mark is needed to keep away generated packets from NFQUEUE. nfqws sets fwmark -when it sends generated packets. nfqws can internally filter marked packets. -but when connbytes filter is used without mark filter packet ordering can be -changed breaking the whole idea of desync attack. - -### DPI desync combos - -`dpi-desync` parameter takes up to 3 comma separated arguments. zero phase -means tcp connection establishement (before sending data payload). Mode can be -`synack`. Hostlist filter is not applicable to the zero phase. Next phases work -on packets with data payload. 1st phase mode can be `fake`,`rst`,`rstack`, 2nd -phase mode - `disorder`,`disorder2`,`split`,`split2`,`ipfrag2`. Can be useful -for ISPs with more than one DPI. - -### SYNACK mode - -In geneva docs it's called *TCP turnaround*. Attempt to make the DPI believe -the roles of client and server are reversed. - -***This mode breaks NAT operation and can be used only if there's no NAT -between the attacker's device and the DPI!*** - -In Linux it's required to remove standard firewall rule dropping INVALID -packets in the OUTPUT chain, for example: -``` --A OUTPUT -m state --state INVALID -j DROP -``` - -In openwrt it's possible to disable the rule for both FORWARD and OUTPUT chains -in `/etc/config/firewall`: -``` -config zone - option name 'wan' - ......... - option masq_allow_invalid '1' -``` - -Unfortunately there's no OUTPUT only switch. It's not desired to remove the -rule from the FORWARD chain. Add the following lines to `/etc/firewall.user`: -``` -iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT -ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT -``` - -Then `/etc/init.d/firewall restart` - -Otherwise raw sending `SYN`, `ACK` frame will cause error stopping the further -processing. If you realize you don't need the synack mode it's highly suggested -to restore drop INVALID rule. - -### Virtual Machines - -Most of nfqws packet magic does not work from VMs powered by virtualbox and -vmware when network is NATed. Hypervisor forcibly changes ttl and does not -forward fake packets. Set up bridge networking. - -### CONNTRACK - -`nfqws` is equipped with minimalistic connection tracking system (conntrack) It's -enabled if some specific DPI circumvention methods are involved. - -Currently these are `--wssize` and `--dpi-desync-cutoff` options. - -Conntrack can track connection phase: `SYN`, `ESTABLISHED`, `FIN`, packet -counts in both directions, sequence numbers. - -It can be fed with unidirectional or bidirectional packets. - -A `SYN` or `SYN,ACK` packet creates an entry in the conntrack table. That's why -iptables redirection must start with the first packet although can be cut later -using connbytes filter. - -First seen UDP packet creates UDP stream. It defines the stream direction. Then -all packets with the same `src_ip,src_port,dst_ip,dst_port` are considered to -belong to the same UDP stream. UDP stream exists till inactivity timeout. - -A connection is deleted from the table as soon as it's no more required to -satisfy `nfqws` needs or when a timeout happens. - -There're 3 timeouts for each connection state. They can be changed in -`--ctrack-timeouts` parameter. - -`--wssize` changes tcp window size for the server to force it to send split -replies. In order for this to affect all server operating systems, it is -necessary to change the window size in each outgoing packet before sending the -message, the answer to which must be split (for example, TLS ClientHello). -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. -If you deal with a non-HTTP(s) protocol you need `--wssize-cutoff`. It sets the -threshold where wssize stops. - -Threshold can be prefixed with 'n' (packet number starting from 1), 'd' (data -packet number starting from 1), '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. - -If your protocol is prone to long inactivity, you should increase ESTABLISHED -phase timeout using `--ctrack-timeouts`. - -Default timeout is low - only 5 mins. - -Don't forget that `nfqws` feeds with redirected packets. If you have limited -redirection with connbytes ESTABLISHED entries can remain in the table until -dropped by timeout. - -To diagnose conntrack state send SIGUSR1 signal to `nfqws`: -``` -killall -SIGUSR1 nfqws -``` - -`nfqws` will dump current conntrack table to stdout. - -Typically, in a `SYN` packet, client sends TCP extension **scaling factor** in -addition to window size. scaling factor is the power of two by which the window -size is multiplied : 0=>1, 1=>2, 2=>4, ..., 8=>256, ... - -The wssize parameter specifies the scaling factor after a colon. - -Scaling factor can only decrease, increase is blocked to prevent the server -from exceeding client's window size. - -To force a TLS server to fragment ServerHello message to avoid hostname -detection on DPI use `--wssize=1:6` - -The main rule is to set scale_factor as much as possible so that after recovery -the final window size becomes the possible maximum. If you set `scale_factor` -64:0, it will be very slow. - -On the other hand, the server response must not be large enough for the DPI to -find what it is looking for. - -Hostlist filter does not affect `--wssize` because it works since the -connection initiation when it's not yet possible to extract the host name. - -`--wssize` may slow down sites and/or increase response time. It's desired to -use another methods if possible. - -`--dpi-desync-cutoff` allows you to set the threshold at which it stops -applying dpi-desync. Can be prefixed with 'n', 'd', 's' symbol the same way as -`--wssize-cutoff`. Useful with `--dpi-desync-any-protocol=1`. If the connection -falls out of the conntrack and --dpi-desync-cutoff is set, dpi desync will not -be applied. - -Set conntrack timeouts appropriately. - -### 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`. - -`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. Requires that -application protocol does not depend on udp payload size. - -QUIC initial packets are recognized. Decryption and hostname extraction is -supported so `--hostlist` parameter will work. Wireguard handshake initiation -and DHT packets are also recognized. For other protocols desync use -`--dpi-desync-any-protocol`. - -Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout -can be set in the 4th parameter of `--ctrack-timeouts`. - -Fake attack is useful only for stateful DPI and useless for stateless dealing -with each packet independently. By default fake payload is 64 zeroes. Can be -overriden using `--dpi-desync-fake-unknown-udp`. - -### IP fragmentation - -Modern network is very hostile to IP fragmentation. Fragmented packets are -often not delivered or refragmented/reassembled on the way. Frag position is -set independently for tcp and udp. By default 24 and 8, must be multiple of 8. -Offset starts from the transport header. - -There are important nuances when working with fragments in Linux. - -`ipv4`: Linux allows to send ipv4 fragments but standard firewall rules in -OUTPUT chain can cause raw send to fail. - -`ipv6`: There's no way for an application to reliably send fragments without -defragmentation by conntrack. Sometimes it works, sometimes system defragments -packets. Looks like kernels older than 4.16 have no simple way to solve this -problem. Unloading of `nf_conntrack` module and its dependency `nf_defrag_ipv6` -helps but this severely impacts functionality. Kernels 4.16+ exclude from -defragmentation untracked packets. See `blockcheck.sh` code for example. - -Sometimes it's required to load `ip6table_raw` kernel module with parameter -`raw_before_defrag=1`. In openwrt module parameters are specified after module -names separated by space in files located in `/etc/modules.d`. - -In traditional Linux check whether `iptables-legacy` or `iptables-nft` is used. -If legacy create the file `/etc/modprobe.d/ip6table_raw.conf` with the -following content : -``` -options ip6table_raw raw_before_defrag=1 -``` - -In some Linux distros its possible to change current ip6tables using this -command: `update-alternatives --config ip6tables`. If you want to stay with -`nftables-nft` you need to patch and recompile your version. In `nft.c` find : -``` - { - .name = "PREROUTING", - .type = "filter", - .prio = -300, /* NF_IP_PRI_RAW */ - .hook = NF_INET_PRE_ROUTING, - }, - { - .name = "OUTPUT", - .type = "filter", - .prio = -300, /* NF_IP_PRI_RAW */ - .hook = NF_INET_LOCAL_OUT, - }, -``` -and replace -300 to -450. - -It must be done manually, `blockcheck.sh` cannot auto fix this for you. - -Or just move to `nftables`. You can create hooks with any priority there. - -Looks like there's no way to do ipfrag using iptables for forwarded traffic if -NAT is present. `MASQUERADE` is terminating target, after it `NFQUEUE` does not -work. `nfqws` sees packets with internal network source address. If fragmented -NAT does not process them. This results in attempt to send packets to internet -with internal IP address. You need to use nftables instead with hook priority -101 or higher. - - -## `tpws` - -`tpws` is transparent proxy. - -``` - --debug=0|1|2 ; 0(default)=silent 1=verbose 2=debug - --bind-addr=| ; For v6 link locals append %interface_name : fe80::1%br-lan - --bind-iface4= ; Bind to the first ipv4 addr of interface - --bind-iface6= ; Bind to the first ipv6 addr of interface - --bind-linklocal=no|unwanted|prefer|force ; No : bind only to global ipv6 - ; Unwanted (default) : prefer global address, then LL - ; Prefer : prefer LL, then global - ; Force : LL only - --bind-wait-ifup= ; Wait for interface to appear and up - --bind-wait-ip= ; After ifup wait for ip address to appear up to N seconds - --bind-wait-ip-linklocal= ; Accept only link locals first N seconds then any - --bind-wait-only ; Wait for bind conditions satisfaction then exit. return code 0 if success. - --port= ; Port number to listen on - --socks ; Implement socks4/5 proxy instead of transparent proxy - --local-rcvbuf= ; SO_RCVBUF for local legs - --local-sndbuf= ; SO_SNDBUF for local legs - --remote-rcvbuf= ; SO_RCVBUF for remote legs - --remote-sndbuf= ; SO_SNDBUF for remote legs - --skip-nodelay ; Do not set TCP_NODELAY for outgoing connections. incompatible with split. - --no-resolve ; Disable socks5 remote dns - --maxconn= ; Max number of local legs - --maxfiles= ; Max file descriptors (setrlimit). min requirement is (X*connections+16), where X=6 in tcp proxy mode, X=4 in tampering mode. - ; Its worth to make a reserve with 1.5 multiplier. by default maxfiles is (X*connections)*1.5+16 - --max-orphan-time= ; If local leg sends something and closes and remote leg is still connecting then cancel connection attempt after N seconds - --hostlist= ; Only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) - --hostlist-exclude= ; Do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) - --split-http-req=method|host ; Split http request at specified logical position. - --split-pos= ; Split at specified pos. split-http-req takes precedence over split-pos for http reqs. - --split-any-protocol ; Split not only http and https - --disorder ; When splitting simulate sending second fragment first - --hostcase ; Change Host: => host: - --hostspell ; Exact spelling of "Host" header. must be 4 chars. default is "host" - --hostdot ; Add "." after Host: name - --hosttab ; Add tab after Host: name - --hostnospace ; Remove space after Host: - --hostpad= ; Add dummy padding headers before Host: - --domcase ; Mix domain case after Host: like this : TeSt.cOm - --methodspace ; Add extra space after method - --methodeol ; Add end-of-line before method - --unixeol ; Replace 0D0A to 0A - --daemon ; Daemonize - --pidfile= ; Write pid to file - --user= ; Drop root privs - --uid=uid[:gid] ; Drop root privs -``` - -The manipulation parameters can be combined in any way. - -`split-http-req` takes precedence over `split-pos` for HTTP reqs. - -`split-pos` works by default only on HTTP and TLS ClientHello. use -`--split-any-protocol` to act on any packet - -`tpws` can bind to multiple interfaces and IP addresses (up to 32). - -Port number is always the same. - -Parameters `--bind-iface*` and `--bind-addr` create new bind. - -Other parameters `--bind-*` are related to the last bind. - -Link local ipv6 (`fe80::/8`) mode selection: -``` ---bind-iface6 --bind-linklocal=no : first selects private address fc00::/7, then global address ---bind-iface6 --bind-linklocal=unwanted : first selects private address fc00::/7, then global address, then LL ---bind-iface6 --bind-linklocal=prefer : first selects LL, then private address fc00::/7, then global address ---bind-iface6 --bind-linklocal=force : select only LL -``` - -To bind to all ipv4 specify `--bind-addr "0.0.0.0"`, all ipv6 - `::`. - -`--bind-addr=""` - mean bind to all ipv4 and ipv6. - -If no binds are specified default bind to all ipv4 and ipv6 addresses is -created. - -To bind to a specific link local address do : -`--bind-iface6=fe80::aaaa:bbbb:cccc:dddd%iface-name` - -The `--bind-wait*` parameters can help in situations where you need to get IP -from the interface, but it is not there yet, it is not raised or not -configured. - -In different systems, ifup events are caught in different ways and do not -guarantee that the interface has already received an IP address of a certain -type. - -In the general case, there is no single mechanism to hang oneself on an event -of the type "link local address appeared on the X interface." - -To bind to a specific ip when its interface may not be configured yet do: -`--bind-addr=192.168.5.3 --bind-wait-ip=20` - -It's possible to bind to any nonexistent address in transparent mode but in -socks mode address must exist. - -In socks proxy mode no additional system privileges are required. Connections -to local IPs of the system where tpws runs are prohibited. tpws supports remote -dns resolving (curl : `--socks5-hostname` firefox : `socks_remote_dns=true`), -but does it in blocking mode. - -`tpws` uses async sockets for all activity but resolving can break this model. - -if `tpws` serves many clients it can cause trouble. also DoS attack is possible -against `tpws`. - -if remote resolving causes trouble configure clients to use local name -resolution and use `--no-resolve` option on `tpws` side. - -`--disorder` is an additional flag to any split option. It tries to simulate -`--disorder2` option of `nfqws` using standard socket API without the need of -additional privileges. This works fine in Linux and MacOS but unexpectedly in -FreeBSD and OpenBSD (system sends second fragment then the whole packet instead -of the first fragment). - -## Ways to get a list of blocked IP - -nftables can't work with ipsets. Native nf sets require lots of RAM to load -large ip lists with subnets and intervals. In case you're on a low RAM system -and need large lists it may be required to fall back to iptables+ipset. - -1. Enter the blocked domains to `ipset/zapret-hosts-user.txt` and run - `ipset/get_user.sh` At the output, you get `ipset/zapret-ip-user.txt` with - IP addresses. -2. `ipset/get_reestr_*.sh`. Russian specific -3. `ipset/get_antifilter_*.sh`. Russian specific -4. `ipset/get_config.sh`. This script calls what is written into the GETLIST - variable from the config file. - -If the variable is not defined, then only lists for ipsets nozapret/nozapret6 -are resolved. - -So, if you're not russian, the only way for you is to manually add blocked -domains. Or write your own `ipset/get_iran_blocklist.sh` , if you know where to -download this one. - -On routers, it is not recommended to call these scripts more than once in 2 -days to minimize flash memory writes. - -`ipset/create_ipset.sh` executes forced `ipset` update. With `no-update` -parameter `create_ipset.sh` creates `ipset` but populate it only if it was -actually created. - -It's useful when multiple subsequent calls are possible to avoid wasting of cpu -time redoing the same job. - -Ipset loading is resource consuming. Its a good idea to call create_ipset -without `no-update` parameter - -only once a several days. Use it with `no-update` option in other cases. - -`ipset` scripts automatically call ip2net utility. ip2net helps to reduce ip list -size by combining IPs to subnets. Also it cuts invalid IPs from the list. -Stored lists are already processed by ip2net. They are error free and ready for -loading. - -`create_ipset.sh` supports loading ip lists from gzip files. First it looks for -the filename with the ".gz" extension, such as `zapret-ip.txt.gz`, if not found -it falls back to the original name `zapret-ip.txt`. - -So your own get_iran_blockslist.sh can use "zz" function to produce gz. Study -how other russian `get_XXX.sh` work. - -Gzipping helps saving a lot of precious flash space on embedded systems. - -User lists are not gzipped because they are not expected to be very large. - -You can add a list of domains to `ipset/zapret-hosts-user-ipban.txt`. Their ip -addresses will be placed in a separate `ipset` "ipban". It can be used to route -connections to transparent proxy "redsocks" or VPN. - -IPV6: if ipv6 is enabled, then additional txt's are created with the same name, -but with a "6" at the end before the extension. - -`zapret-ip.txt` => `zapret-ip6.txt` - -The ipsets zapret6 and ipban6 are created. - -IP EXCLUSION SYSTEM. All scripts resolve `zapret-hosts-user-exclude.txt` file, -creating `zapret-ip-exclude.txt` and `zapret-ip-exclude6.txt`. - -They are the source for ipsets nozapret/nozapret6. All rules created by init -scripts are created with these ipsets in mind. The IPs placed in them are not -involved in the process. zapret-hosts-user-exclude.txt can contain domains, -ipv4 and ipv6 addresses or subnets. - -FreeBSD. `ipset/*.sh` scripts also work in FreeBSD. Instead of `ipset` they -create ipfw lookup tables with the same names as in Linux. ipfw tables can -store both ipv4 and ipv6 addresses and subnets. There's no 4 and 6 separation. - -LISTS_RELOAD config parameter defines a custom lists reloading command. Its -useful on BSD systems with PF. LISTS_RELOAD=- disables reloading ip list -backend. - - -## Domain name filtering - -An alternative to `ipset` is to use tpws or `nfqws` with a list(s) of domains. Both -`tpws` and `nfqws` take any number of include (`--hostlist`) and exclude -(`--hostlist-exclude`) domain lists. All lists of the same type are combined -internally leaving only 2 lists : include and exclude. - -Exclude list is checked first. Fooling is cancelled if domain belongs to -exclude list. If include list is present and domain does not belong to that -list fooling is also cancelled. Empty list means absent list. Otherwise fooling -goes on. - -Launch system looks for 2 include lists : - -`ipset/zapret-hosts-users.txt.gz` or `ipset/zapret-hosts-users.txt` - -`ipset/zapret-hosts.txt.gz` or `ipset/zapret-hosts.txt` - -and 1 exclude list - -`ipset/zapret-hosts-users-exclude.txt.gz` or `ipset/zapret-hosts-users-exclude.txt` - -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" . - -tpws and `nfqws` reread lists on HUP signal. - -When filtering by domain name, daemons should run without filtering by `ipset`. -When using large regulator lists estimate the amount of RAM on the router ! - -## Choosing parameters - -The file `/opt/zapret/config` is used by various components of the system and -contains basic settings. It needs to be viewed and edited if necessary. - -Which firewall type use on Linux systems : `nftables` or `iptables`. On -traditional systems `nftables` is selected by default if `nft` is installed. On -openwrt by default `nftables` is selected on `firewall4` based systems. - -`FWTYPE=iptables` - -Main mode: -``` -tpws - tpws transparent mode -tpws-socks - tpws socks mode, binds to localhost and LAN interface (if IFACE_LAN is specified or the system is OpenWRT). port 988 -nfqws - nfqws -filter - only fill ipset or load hostlist -custom - use custom script for running daemons and establishing firewall rules -``` - -`MODE=tpws` - -Enable HTTP fooling: -`MODE_HTTP=1` - -Apply fooling to keep alive HTTP sessions. Only applicable to `nfqws`. Tpws -always fool keepalives. Not enabling this can save CPU time. -`MODE_HTTP_KEEPALIVE=0` - -Enable HTTPS fooling: -`MODE_HTTPS=1` - -Enable QUIC fooling: -`MODE_QUIC=1` - -Host filtering mode: -``` -none - apply fooling to all hosts -ipset - limit fooling to hosts from ipset zapret/zapret6 -hostlist - limit fooling to hosts from hostlist -``` - -`MODE_FILTER=none` - -Its possible to change manipulation options used by `tpws`: -`TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3"` - -`nfqws` options for DPI desync attack: -``` -DESYNC_MARK=0x40000000 -NFQWS_OPT_DESYNC="--dpi-desync=fake --dpi-desync-ttl=0 --dpi-desync-fooling=badsum --dpi-desync-fwmark=$DESYNC_MARK" -``` - -Separate `nfqws` options for HTTP and HTTPS and ip protocol versions 4,6: -``` -NFQWS_OPT_DESYNC_HTTP="--dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" -NFQWS_OPT_DESYNC_HTTPS="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" -NFQWS_OPT_DESYNC_HTTP6="--dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" -NFQWS_OPT_DESYNC_HTTPS6="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" -``` - -If one of `NFQWS_OPT_DESYNC_HTTP`/`NFQWS_OPT_DESYNC_HTTPS` is not defined it -takes value of NFQWS_OPT_DESYNC. If one of -`NFQWS_OPT_DESYNC_HTTP6`/`NFQWS_OPT_DESYNC_HTTPS6` is not defined it takes -value from `NFQWS_OPT_DESYNC_HTTP`/`NFQWS_OPT_DESYNC_HTTPS`. It means if only -`NFQWS_OPT_DESYNC` is defined all four take its value. - -If a variable is not defined, the value `NFQWS_OPT_DESYNC` is taken. - -Separate QUIC options for ip protocol versions: -``` -NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake" -NFQWS_OPT_DESYNC_QUIC6="--dpi-desync=hopbyhop" -``` - -If `NFQWS_OPT_DESYNC_QUIC6` is not specified `NFQWS_OPT_DESYNC_QUIC` is taken. - -Flow offloading control (if supported): -``` -donttouch : disable system flow offloading setting if selected mode is incompatible with it, dont touch it otherwise and dont configure selective flow offloading -none : always disable system flow offloading setting and dont configure selective flow offloading -software : always disable system flow offloading setting and configure selective software flow offloading -hardware : always disable system flow offloading setting and configure selective hardware flow offloading -``` - -`FLOWOFFLOAD=donttouch` - -The GETLIST parameter tells the install_easy.sh installer which script to call -to update the list of blocked ip or hosts. Its called via `get_config.sh` from -scheduled tasks (crontab or systemd timer). Put here the name of the script -that you will use to update the lists. If not, then the parameter should be -commented out. - -You can individually disable ipv4 or ipv6. If the parameter is commented out or -not equal to "1", use of the protocol is permitted. -``` -#DISABLE_IPV4=1 -DISABLE_IPV6=1 -``` - -The number of threads for mdig multithreaded DNS resolver (1..100). The more of -them, the faster, but will your DNS server be offended by hammering? -``` -MDIG_THREADS=30 -``` - -Temp directory. Used by `ipset/*.sh` scripts for large lists processing. /tmp by -default. Can be reassigned if /tmp is tmpfs and RAM is low. -``` -TMPDIR=/opt/zapret/tmp -``` - -`ipset` and nfset options: -``` -SET_MAXELEM=262144 -IPSET_OPT="hashsize 262144 maxelem 2097152 -``` - -Kernel automatically increases hashsize if `ipset` is too large for the current -hashsize. This procedure requires internal reallocation and may require -additional memory. On low RAM systems it can cause errors. Do not use too high -hashsize. This way you waste your RAM. And dont use too low hashsize to avoid -reallocs. - -ip2net options. separate for ipv4 and ipv6. -``` -IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4" -IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5" -``` - -Enable gzip compression for large lists. Used by `ipset/*.sh` scripts. -`GZIP_LISTS=1` - -Command to reload ip/host lists after update. Comment or leave empty for auto -backend selection: `ipset` or `ipfw` if present. On BSD systems with PF no auto -reloading happens. You must provide your own command. Newer FreeBSD versions -support table only reloading : `pfctl -Tl -f /etc/pf.conf` Set to "-" to -disable reload. - -`LISTS_RELOAD="pfctl -f /etc/pf.conf"` - -In openwrt there's default network `lan`. Only traffic coming from this network -is redirected to tpws by default. To override this behaviour set the following -variable: -`OPENWRT_LAN="lan lan2 lan3"` - -The `INIT_APPLY_FW=1` parameter enables the init script to independently apply -iptables rules. With other values or if the parameter is commented out, the -rules will not be applied. This is useful if you have a firewall management -system, in the settings of which you should tie the rules. Not applicable to -`OpenWRT` if used with `firewall3+iptables`. - -The following settings are not relevant for openwrt: - -If your system works as a router, then you need to enter the names of the -internal and external interfaces: -``` -IFACE_LAN=eth0 -IFACE_WAN=eth1 -IFACE_WAN6="henet ipsec0" -``` -Multiple interfaces are space separated. IF IFACE_WAN6 is omitted then -IFACE_WAN value is taken. - -**IMPORTANT**: -Configuring routing, masquerade, etc. not a zapret task. Only modes -that intercept transit traffic are enabled. It's possible to specify multiple -interfaces like this : `IFACE_LAN="eth0 eth1 eth2"` - - -## Screwing to the firewall control system or your launch system - -If you use some kind of firewall management system, then it may conflict with -an existing startup script. When re-applying the rules, it could break the -iptables settings from the zapret. In this case, the rules for iptables should -be screwed to your firewall separately from running tpws or `nfqws`. - -The following calls allow you to apply or remove iptables rules separately: -``` - /opt/zapret/init.d/sysv/zapret start_fw - /opt/zapret/init.d/sysv/zapret stop_fw - /opt/zapret/init.d/sysv/zapret restart_fw -``` - -And you can start or stop the demons separately from the firewall: -``` - /opt/zapret/init.d/sysv/zapret start_daemons - /opt/zapret/init.d/sysv/zapret stop_daemons - /opt/zapret/init.d/sysv/zapret restart_daemons -``` - -nftables nearly eliminate conflicts betweeen firewall control systems because -they allow separate tables and netfilter hooks. `zapret` nf table is used for -zapret purposes. If your system does not touch it everything will likely be OK. - -Some additional nftables-only calls exist: - -Lookup `lanif`, `wanif`, `wanif6` and `flow table` interface sets. -``` - /opt/zapret/init.d/sysv/zapret list_ifsets -``` - -Renew `lanif`, `wanif`, `wanif6` and `flow table` interface sets. Taken from -`IFACE_LAN`, `IFACE_WAN` config variables on traditional Linux systems. -Autoselected on `OpenWRT`. `lanif` can be extended using `OPENWRT_LAN` config -variable. -``` - /opt/zapret/init.d/sysv/zapret reload_ifsets -``` - -Calls `nft -t list table inet zapret`. -``` - /opt/zapret/init.d/sysv/zapret list_table -``` - -It's also possible to hook with your script to any stage of zapret firewall -processing. The following settings are available in the zapret config file: -``` -INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up" -INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up" -INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down" -INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down" -``` - -Hooks are extremely useful if you need nftables sets populated by zapret -scripts. nfsets can only belong to one table. You have to write rule there and -synchorize them with zapret scripts. - - -## Installation - -### Checking ISP - -Before running zapret you must discover working bypass strategy. -`blockcheck.sh` automates this process. It first checks DNS then tries many -strategies finding the working ones. Note that DNS check is mostly Russia -targeted. It checks several pre-defined blocked in Russia domains and verifies -system DNS answers with public DNS answers. Because ISP can block public DNS or -redirect any DNS queries to their servers `blockcheck.sh` also checks that all -returned answers are unique. Usually if DNS is blocked ISP returns single ip -for all blocked domains to redirect you to their "access denied" page. -`blockcheck.sh` works in Linux and FreeBSD. - -### Desktop Linux system - -Simple install works on most modern Linux distributions with systemd or openrc, -OpenWRT and MacOS. Run `install_easy.sh` and answer its questions. - -### OpenWRT - -`install_easy.sh` works on openwrt but there're additional challenges. They are -mainly about possibly low flash free space. Simple install will not work if it -has no space to install itself and required packages from the repo. - -Another challenge would be to bring zapret to the router. You can download zip -from github and use it. Do not repack zip contents in Windows, because this way -you break chmod and links. Install openssh-sftp-server and unzip to openwrt and -use sftp to transfer the file. - -The best way to start is to put zapret dir to `/tmp` and run -`/tmp/zapret/install_easy.sh` from there. After installation remove -`/tmp/zapret` to free RAM. - -The absolute minimum for openwrt is 64/8 system, 64/16 is comfortable, -128/extroot is recommended. - -### Android - -Its not possible to use `nfqws` and tpws in transparent proxy mode without root -privileges. Without root tpws can run in --socks mode. - -Android has NFQUEUE and `nfqws` should work. - -There's no `ipset` support unless you run custom kernel. In common case task of -bringing up `ipset` on android is ranging from "not easy" to "almost impossible", -unless you find working kernel image for your device. - -Android does not use /etc/passwd, `tpws --user` won't work. There's -replacement. Use numeric uids in `--uid` option. Its recommended to use gid -3003 (AID_INET), otherwise tpws will not have inet access. - -Example : `--uid 1:3003` - -In iptables use : `! --uid-owner 1` instead of `! --uid-owner tpws`. - -`nfqws` should be executed with `--uid 1`. Otherwise on some devices or firmwares -kernel may partially hang. Looks like processes with certain uids can be -suspended. With buggy chineese cellular interface driver this can lead to -device hang. - -Write your own shell script with iptables and tpws, run it using your root -manager. - -Autorun scripts are here: -Magisk: `/data/adb/service.d` -Supersu: `/system/su.d` - -How to run tpws on root-less android. You can't write to `/system`, `/data`, -can't run from sd card. SeLinux prevents running executables in -`/data/local/tmp` from apps. Use adb and adb shell. - -``` -mkdir /data/local/tmp/zapret -adb push tpws /data/local/tmp/zapret -chmod 755 /data/local/tmp/zapret /data/local/tmp/zapret/tpws -chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws -``` - -Now its possible to run `/data/local/tmp/zapret/tpws` from any app such as tasker. - -### FreeBSD, OpenBSD, MacOS - -See [BSD documentation](./bsd.eng.md). - -### Windows (WSL) - -Using WSL (Windows subsystem for Linux) it's possible to run tpws in socks mode -under rather new builds of windows 10 and windows server. Its not required to -install any Linux distributions as suggested in most articles. 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. - -Run: -``` -wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz -``` - -Run tpws: -``` -wsl --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 -``` - -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). - -**NOTICE**: -There is native windows solution GoodByeDPI. It works on packet level like -`nfqws`. - -### Other devices - -Author's goal does not include easy supporting as much devices as possibles. -Please do not ask for easy supporting firmwares. It requires a lot of work and -owning lots of devices. Its counterproductive. As a devices owner its easier -for you and should not be too hard if firmware is open. Most closed stock -firmwares are not designed for custom usage and sometimes actively prevent it. -In the latter case you have to hack into it and reverse engineer. Its not easy. -Binaries are universal. They can run on almost all firmwares. - -You will need: - * Root shell access. true sh shell, not microtik-like console - * Startup hook - * r/w partition to store binaries and startup script with executable - permission (+x) - * `tpws` can be run almost anywhere but `nfqws` require kernel support for - NFQUEUE. Its missing in most firmwares. - * Kernels older than 2.6 are unsupported and can cause errors. Newer kernels - are OK. - -If binaries crash with segfault (rare but happens on some kernels) try to -unpack `upx` like this: -``` -upx -d tpws -``` - -First manually debug your scenario. Run iptables + daemon and check if its what -you want. Write your own script with iptables magic and run required daemon -from there. Put it to startup. Dont ask me how to do it. Its different for all -firmwares and requires studying. Find manual or reverse engineer yourself. -Check for race conditions. Firmware can clear or modify iptables after your -startup script. If this is the case then run another script in background and -add some delay there. - +## What is it for + +A stand-alone (without 3rd party servers) DPI circumvention tool. +May allow to bypass http(s) website blocking or speed shaping, resist signature tcp/udp protocol discovery. + +The project is mainly aimed at the Russian audience to fight russian regulator named "Roskomnadzor". +Some features of the project are russian reality specific (such as getting list of sites +blocked by Roskomnadzor), but most others are common. + +Mainly OpenWRT targeted but also supports traditional Linux, FreeBSD, OpenBSD, partially MacOS. + +## How it works + +In the simplest case you are dealing with passive DPI. Passive DPI can read passthrough traffic, +inject its own packets, but cannot drop packets. + +If the request is prohibited the passive DPI will inject its own RST packet and optionally http redirect packet. + +If fake packets from DPI are only sent to client, you can use iptables commands to drop them if you can write +correct filter rules. This requires manual in-deep traffic analysis and tuning for specific ISP. + +This is how we bypass the consequences of a ban trigger. + +If the passive DPI sends an RST packet also to the server, there is nothing you can do about it. +Your task is to prevent ban trigger from firing up. Iptables alone will not work. +This project is aimed at preventing the ban rather than eliminating its consequences. + +To do that send what DPI does not expect and what breaks its algorithm of recognizing requests and blocking them. + +Some DPIs cannot recognize the http request if it is divided into TCP segments. +For example, a request of the form `GET / HTTP / 1.1 \ r \ nHost: kinozal.tv ......` +we send in 2 parts: first go `GET`, then `/ HTTP / 1.1 \ r \ nHost: kinozal.tv .....`. + +Other DPIs stumble when the `Host:` header is written in another case: for example, `host:`. + +Sometimes work adding extra space after the method: `GET /` => `GET /` +or adding a dot at the end of the host name: `Host: kinozal.tv.` + +There is also more advanced magic for bypassing DPI at the packet level. + +## How to put this into practice in the linux system + +In short, the options can be classified according to the following scheme: + +1. Passive DPI not sending RST to the server. ISP tuned iptables commands can help. +This option is out of the scope of the project. If you do not allow ban trigger to fire, then you won’t have to +deal with its consequences. +2. Modification of the TCP connection at the stream level. Implemented through a proxy or transparent proxy. +3. Modification of TCP connection at the packet level. Implemented through the NFQUEUE handler and raw sockets. + +For options 2 and 3, tpws and nfqws programs are implemented, respectively. +You need to run them with the necessary parameters and redirect certain traffic with iptables or nftables. + +To redirect a TCP connection to a transparent proxy, the following commands are used: + +forwarded traffic : +`iptables -t nat -I PREROUTING -i -p tcp --dport 80 -j DNAT --to 127.0.0.127:988` + +outgoing traffic : +`iptables -t nat -I OUTPUT -o -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988` + +DNAT on localhost works in the OUTPUT chain, but does not work in the PREROUTING chain without enabling the route_localnet parameter: + +`sysctl -w net.ipv4.conf..route_localnet=1` + +You can use `-j REDIRECT --to-port 988` instead of DNAT, but in this case the transparent proxy process +should listen on the ip address of the incoming interface or on all addresses. Listen all - not good +in terms of security. Listening one (local) is possible, but automated scripts will have to recognize it, +then dynamically enter it into the command. In any case, additional efforts are required. +Using route_localnet can also introduce some security risks. You make available from internal_interface everything +bound to `127.0.0.0/8`. Services are usually bound to `127.0.0.1`. Its possible to deny input to `127.0.0.1` from all interfaces except lo +or bind tpws to any other IP from `127.0.0.0/8` range, for example to `127.0.0.127`, and allow incomings only to that IP : + +``` +iptables -A INPUT ! -i lo -d 127.0.0.127 -j ACCEPT +iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j DROP +``` + +Owner filter is necessary to prevent recursive redirection of connections from tpws itself. +tpws must be started under OS user `tpws`. + +NFQUEUE redirection of the outgoing traffic and forwarded traffic going towards the external interface, +can be done with the following commands: + +`iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -j NFQUEUE --queue-num 200 --queue-bypass` + +In order not to touch the traffic to unblocked addresses, you can take a list of blocked hosts, resolve it +into IP addresses and put them to ipset 'zapret', then add a filter to the command: + +`iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass` + +Some DPIs catch only the first http request, ignoring subsequent requests in a keep-alive session. +Then we can reduce CPU load, refusing to process unnecessary packets. + +`iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass` + +Mark filter does not allow nfqws-generated packets to enter the queue again. +Its necessary to use this filter when also using `connbytes 1:4`. Without it packet ordering can be changed breaking the whole idea. + +## ip6tables + +ip6tables work almost exactly the same way as ipv4, but there are a number of important nuances. +In DNAT, you should take the address --to in square brackets. For example : + + `ip6tables -t nat -I OUTPUT -o -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to [::1]:988` + +The route_localnet parameter does not exist for ipv6. +DNAT to localhost (:: 1) is possible only in the OUTPUT chain. +In the PREROUTING DNAT chain, it is possible to any global address or to the link local address of the same interface +the packet came from. +NFQUEUE works without changes. + + +## nftables + +nftables are fine except one very big problem. +nft requires tons of RAM to load large nf sets (ip lists) with subnets/intervals. Most of the home routers can't afford that. +For example, even a 256 Mb system can't load a 100K ip list. nft process will OOM. +nf sets do not support overlapping intervals and that's why nft process applies very RAM consuming algorithm to merge intervals so they don't overlap. +There're equivalents to iptables for all other functions. Interface and protocol anonymous sets allow not to write multiple similar rules. +Flow offloading is built-in into new linux kernels and nft versions. + +nft version `1.0.2` or higher is recommended. + + +## When it will not work + +* If DNS server returns false responses. ISP can return false IP addresses or not return anything +when blocked domains are queried. If this is the case change DNS to public ones, such as 8.8.8.8 or 1.1.1.1.Sometimes ISP hijacks queries to any DNS server. Dnscrypt or dns-over-tls help. +* If blocking is done by IP. +* If a connection passes through a filter capable of reconstructing a TCP connection, and which +follows all standards. For example, we are routed to squid. Connection goes through the full OS tcpip stack, fragmentation disappears immediately as a means of circumvention. Squid is correct, it will find everything as it should, it is useless to deceive him. BUT. Only small providers can afford using squid, since it is very resource intensive. Large companies usually use DPI, which is designed for much greater bandwidth. + +## nfqws + +This program is a packet modifier and a NFQUEUE queue handler. +For BSD systems there is dvtws. Its built from the same source and has almost the same parameters (see bsd.eng.md). +nfqws takes the following parameters: + +``` + --debug=0|1 + --qnum= + --daemon ; daemonize + --pidfile= ; write pid to file + --user= ; drop root privs + --uid=uid[:gid] ; 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=[:] ; set window size. 0 = do not modify. OBSOLETE ! + --wssize=[:] ; 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 + --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 + --dpi-desync=[,][,] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper + --dpi-desync-fwmark= ; override fwmark for desync packet. default = 0x40000000 (1073741824) + --dpi-desync-ttl= ; set ttl for desync packet + --dpi-desync-ttl6= ; set ipv6 hop limit for desync packet. by default ttl value is used. + --dpi-desync-fooling=[,] ; can use multiple comma separated values. modes : none md5sig ts badseq badsum hopbyhop hopbyhop2 + --dpi-desync-retrans=0|1 ; 0(default)=reinject original data packet after fake 1=drop original data packet to force its retransmission + --dpi-desync-repeats= ; 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=<1..9216> ; data payload split position + --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= ; badseq fooling seq signed increment. default -10000 + --dpi-desync-badack-increment= ; 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=|0xHEX ; file containing fake http request + --dpi-desync-fake-tls=|0xHEX ; file containing fake TLS ClientHello (for https) + --dpi-desync-fake-unknown=|0xHEX ; file containing unknown protocol fake payload + --dpi-desync-fake-quic=|0xHEX ; file containing fake QUIC Initial + --dpi-desync-fake-wireguard=|0xHEX ; file containing fake wireguard handshake initiation + --dpi-desync-fake-dht=|0xHEX ; file containing fake DHT (d1..e) + --dpi-desync-fake-unknown-udp=|0xHEX ; file containing unknown udp protocol fake payload + --dpi-desync-udplen-increment= ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length. + --dpi-desync-udplen-pattern=|0xHEX ; udp tail fill pattern + --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= ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) + --hostlist-exclude= ; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) +``` + +The manipulation parameters can be combined in any way. + +WARNING. `--wsize` parameter is now not used anymore in scripts. TCP split can be achieved using DPI desync attack. + +### DPI desync attack + +After completion of the tcp 3-way handshake, the first data packet from the client goes. +It usually has `GET / ...` or TLS ClientHello. We drop this packet, replacing with something else. +It can be a fake version with another harmless but valid http or https request (`fake`), tcp reset packet (`rst`,`rstack`), +split into 2 segments original packet with fake segment in the middle (`split`). +`fakeknown` sends fake only in response to known application protocol. +In articles these attack have names **TCB desynchronization** and **TCB teardown**. +Fake packet must reach DPI, but do not reach the destination server. +The following means are available: set a low TTL, send a packet with bad checksum, +add tcp option **MD5 signature**. All of them have their own disadvantages : + +* md5sig does not work on all servers +* 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 + 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. + In openwrt mentioned sysctl is set to 0 from the box, in other routers its often left in the default "1" state. + For nfqws to work properly through the router set `net.netfilter.nf_conntrack_checksum=0` on the router. + System never verifies checksums of locally generated packets so nfqws will always work on the router itself. + If you are behind another NAT, such as a ISP, and it does not pass invalid packages, there is nothing you can do about it. + But usually ISPs pass badsum. + Some adapters/switches/drivers enable hardware filtering of rx badsum not allowing it to pass to the OS. + This behavior was observed on a Mediatek MT7621 based device. + Tried to modify mediatek ethernet driver with no luck, likely hardware enforced limitation. + However the device allowed to send badsum packets, problem only existed for passthrough traffic from clients. +* badseq packets will be dropped by server, but DPI also can ignore them. + default badseq increment is set to -10000 because some DPIs drop packets outside of the small tcp window. + But this also can cause troubles when `--dpi-desync-any-protocol` is enabled. + To be 100% sure fake packet cannot fit to server tcp window consider setting badseq increment to 0x80000000 +* TTL looks like the best option, but it requires special tuning for each ISP. If DPI is further than local ISP websites + you can cut access to them. Manual IP exclude list is required. Its possible to use md5sig with ttl. + This way you cant hurt anything, but good chances it will help to open local ISP websites. + If automatic solution cannot be found then use `zapret-hosts-user-exclude.txt`. + Some router stock firmwares fix outgoing TTL. Without switching this option off TTL fooling will not work. +* `hopbyhop` is ipv6 only. This fooling adds empty extension header `hop-by-hop options` or two headers in case of `hopbyhop2`. + Packets with two hop-by-hop headers violate RFC and discarded by all operating systems. + All OS accept packets with one hop-by-hop header. + Some ISPs/operators drop ipv6 packets with hop-by-hop options. Fakes will not be processed by the server either because + ISP drops them or because there are two same headers. + DPIs may still anaylize packets with one or two hop-by-hop headers. + +`--dpi-desync-fooling` takes multiple comma separated values. + +For fake,rst,rstack modes original packet can be sent after the fake one or just dropped. +If its dropped OS will perform first retransmission after 0.2 sec, then the delay increases exponentially. +Delay can help to make sure fake and original packets are properly ordered and processed on DPI. +When `dpi-desync-retrans=1` its mandatory to use connbytes in iptables rule. Otherwise loop happens. + +Disorder mode splits original packet and sends packets in the following order : +1. 2nd segment +2. fake 1st segment, data filled with zeroes +3. 1st segment +4. fake 1st segment, data filled with zeroes (2nd copy) + +Original packet is always dropped. `--dpi-desync-split-pos` sets split position (default 2). +If position is higher than packet length, pos=1 is used. +This sequence is designed to make reconstruction of critical message as difficult as possible. +Fake segments may not be required to bypass some DPIs, but can potentially help if more sophisticated reconstruction +algorithms are used. +Mode `disorder2` disables sending of fake segments. + +Split mode is very similar to disorder but without segment reordering : + +1. fake 1st segment, data filled with zeroes +2. 1st segment +3. fake 1st segment, data filled with zeroes (2nd copy) +4. 2nd segment + +Mode `split2` disables sending of fake segments. It can be used as a faster alternative to --wsize. + +In `disorder2` and 'split2` modes no fake packets are sent, so ttl and fooling options are not required. + +`hopbyhop`, `destopt` and `ipfrag1` desync modes (they're not the same as `hopbyhop` fooling !) are ipv6 only. One `hop-by-hop`, +`destination options` or `fragment` header is added to all desynced packets. +Extra header increases packet size and can't be applied to the maximum size packets. +If it's not possible to send modified packet original one will be sent. +The idea here is that DPI sees 0 in the next header field of the main ipv6 header and does not +walk through the extension header chain until transport header is found. +`hopbyhop`, `destopt`, `ipfrag1` modes can be used with any second phase mode except `ipfrag1+ipfrag2`. +For example, `hopbyhop,split2` means split original tcp packet into 2 pieces and add hop-by-hop header to both. +With `hopbyhop,ipfrag2` header sequence will be : `ipv6,hop-by-hop,fragment,tcp/udp`. +`ipfrag1` mode may not always work without special preparations. See "IP Fragmentation" notices. + +There are DPIs that analyze responses from the server, particularly the certificate from the ServerHello +that contain domain name(s). The ClientHello delivery confirmation is an ACK packet from the server +with ACK sequence number corresponding to the length of the ClientHello+1. +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). +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. + +Hosts are extracted from plain http request Host: header and SNI of ClientHello TLS message. +Subdomains are applied automatically. gzip lists are supported. + +iptables for performing the attack on the first packet : + +`iptables -t mangle -I POSTROUTING -o -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass` + +This is good if DPI does not track all requests in http keep-alive session. +If it does, then pass all outgoing packets for http and only first data packet for https : + +``` +iptables -t mangle -I POSTROUTING -o -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass +iptables -t mangle -I POSTROUTING -o -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass +``` + +mark is needed to keep away generated packets from NFQUEUE. nfqws sets fwmark when it sends generated packets. +nfqws can internally filter marked packets. but when connbytes filter is used without mark filter +packet ordering can be changed breaking the whole idea of desync attack. + +### DPI desync combos + +dpi-desync parameter takes up to 3 comma separated arguments. +zero phase means tcp connection establishement (before sending data payload). Mode can be `synack`. +Hostlist filter is not applicable to the zero phase. +Next phases work on packets with data payload. +1st phase mode can be `fake`,`rst`,`rstack`, 2nd phase mode - `disorder`,`disorder2`,`split`,`split2`,`ipfrag2`. +Can be useful for ISPs with more than one DPI. + +### SYNACK mode + +In geneva docs it's called **TCP turnaround**. Attempt to make the DPI believe the roles of client and server are reversed. + +!!! This mode breaks NAT operation and can be used only if there's no NAT between the attacker's device and the DPI ! + +In linux it's required to remove standard firewall rule dropping INVALID packets in the OUTPUT chain, +for example : `-A OUTPUT -m state --state INVALID -j DROP` + +In openwrt it's possible to disable the rule for both FORWARD and OUTPUT chains in /etc/config/firewall : +``` +config zone + option name 'wan' + ......... + option masq_allow_invalid '1' +``` +Unfortunately there's no OUTPUT only switch. It's not desired to remove the rule from the FORWARD chain. +Add the following lines to `/etc/firewall.user` : + +``` +iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT +ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT +``` + +then `/etc/init.d/firewall restart` + +Otherwise raw sending SYN,ACK frame will cause error stopping the further processing. +If you realize you don't need the synack mode it's highly suggested to restore drop INVALID rule. + +### Virtual Machines + +Most of nfqws packet magic does not work from VMs powered by virtualbox and vmware when network is NATed. +Hypervisor forcibly changes ttl and does not forward fake packets. +Set up bridge networking. + +### CONNTRACK + +nfqws is equipped with minimalistic connection tracking system (conntrack) +It's enabled if some specific DPI circumvention methods are involved. + +Currently these are `--wssize` and `--dpi-desync-cutoff` options. + +Conntrack can track connection phase : SYN,ESTABLISHED,FIN , packet counts in both directions , sequence numbers. + +It can be fed with unidirectional or bidirectional packets. + +A SYN or SYN,ACK packet creates an entry in the conntrack table. + +That's why iptables redirection must start with the first packet although can be cut later using connbytes filter. + +First seen UDP packet creates UDP stream. It defines the stream direction. Then all packets with the same +`src_ip,src_port,dst_ip,dst_port` are considered to belong to the same UDP stream. UDP stream exists till inactivity timeout. + +A connection is deleted from the table as soon as it's no more required to satisfy nfqws needs or when a timeout happens. + +There're 3 timeouts for each connection state. They can be changed in `--ctrack-timeouts` parameter. + +`--wssize` changes tcp window size for the server to force it to send split replies. +In order for this to affect all server operating systems, it is necessary to change the window size in each outgoing packet +before sending the message, the answer to which must be split (for example, TLS ClientHello). +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. + +If you deal with a non-http(s) protocol you need `--wssize-cutoff`. It sets the threshold where wssize stops. + +Threshold can be prefixed with 'n' (packet number starting from 1), 'd' (data packet number starting from 1), +'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. + +If your protocol is prone to long inactivity, you should increase ESTABLISHED phase timeout using `--ctrack-timeouts`. + +Default timeout is low - only 5 mins. + +Don't forget that nfqws feeds with redirected packets. If you have limited redirection with connbytes +ESTABLISHED entries can remain in the table until dropped by timeout. + +To diagnose conntrack state send SIGUSR1 signal to nfqws : `killall -SIGUSR1 nfqws`. + +nfqws will dump current conntrack table to stdout. + +Typically, in a SYN packet, client sends TCP extension **scaling factor** in addition to window size. +scaling factor is the power of two by which the window size is multiplied : 0=>1, 1=>2, 2=>4, ..., 8=>256, ... + +The wssize parameter specifies the scaling factor after a colon. + +Scaling factor can only decrease, increase is blocked to prevent the server from exceeding client's window size. + +To force a TLS server to fragment ServerHello message to avoid hostname detection on DPI use `--wssize=1:6` + +The main rule is to set scale_factor as much as possible so that after recovery the final window size +becomes the possible maximum. If you set `scale_factor` 64:0, it will be very slow. + +On the other hand, the server response must not be large enough for the DPI to find what it is looking for. + +Hostlist filter does not affect `--wssize` because it works since the connection initiation when it's not yet possible +to extract the host name. + +`--wssize` may slow down sites and/or increase response time. It's desired to use another methods if possible. + +`--dpi-desync-cutoff` allows you to set the threshold at which it stops applying dpi-desync. +Can be prefixed with 'n', 'd', 's' symbol the same way as `--wssize-cutoff`. +Useful with `--dpi-desync-any-protocol=1`. +If the connection falls out of the conntrack and --dpi-desync-cutoff is set, dpi desync will not be applied. + +Set conntrack timeouts appropriately. + +### 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`. + +`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. +Requires that application protocol does not depend on udp payload size. + +QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work. +Wireguard handshake initiation and DHT packets are also recognized. +For other protocols desync use `--dpi-desync-any-protocol`. + +Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`. + +Fake attack is useful only for stateful DPI and useless for stateless dealing with each packet independently. +By default fake payload is 64 zeroes. Can be overriden using `--dpi-desync-fake-unknown-udp`. + +### IP fragmentation + +Modern network is very hostile to IP fragmentation. Fragmented packets are often not delivered or refragmented/reassembled on the way. +Frag position is set independently for tcp and udp. By default 24 and 8, must be multiple of 8. +Offset starts from the transport header. + +There are important nuances when working with fragments in Linux. + +ipv4 : Linux allows to send ipv4 fragments but standard firewall rules in OUTPUT chain can cause raw send to fail. + +ipv6 : There's no way for an application to reliably send fragments without defragmentation by conntrack. +Sometimes it works, sometimes system defragments packets. +Looks like kernels <4.16 have no simple way to solve this problem. Unloading of `nf_conntrack` module +and its dependency `nf_defrag_ipv6` helps but this severely impacts functionality. +Kernels 4.16+ exclude from defragmentation untracked packets. +See `blockcheck.sh` code for example. + +Sometimes it's required to load `ip6table_raw` kernel module with parameter `raw_before_defrag=1`. +In openwrt module parameters are specified after module names separated by space in files located in `/etc/modules.d`. + +In traditional linux check whether `iptables-legacy` or `iptables-nft` is used. If legacy create the file +`/etc/modprobe.d/ip6table_raw.conf` with the following content : +``` +options ip6table_raw raw_before_defrag=1 +``` +In some linux distros its possible to change current ip6tables using this command: `update-alternatives --config ip6tables`. +If you want to stay with `nftables-nft` you need to patch and recompile your version. +In `nft.c` find : +``` + { + .name = "PREROUTING", + .type = "filter", + .prio = -300, /* NF_IP_PRI_RAW */ + .hook = NF_INET_PRE_ROUTING, + }, + { + .name = "OUTPUT", + .type = "filter", + .prio = -300, /* NF_IP_PRI_RAW */ + .hook = NF_INET_LOCAL_OUT, + }, +``` +and replace -300 to -450. + +It must be done manually, `blockcheck.sh` cannot auto fix this for you. + +Or just move to `nftables`. You can create hooks with any priority there. + +Looks like there's no way to do ipfrag using iptables for forwarded traffic if NAT is present. +`MASQUERADE` is terminating target, after it `NFQUEUE` does not work. +nfqws sees packets with internal network source address. If fragmented NAT does not process them. +This results in attempt to send packets to internet with internal IP address. +You need to use nftables instead with hook priority 101 or higher. + + +## tpws + +tpws is transparent proxy. + +``` + --debug=0|1|2 ; 0(default)=silent 1=verbose 2=debug + --bind-addr=|; for v6 link locals append %interface_name : fe80::1%br-lan + --bind-iface4= ; bind to the first ipv4 addr of interface + --bind-iface6= ; bind to the first ipv6 addr of interface + --bind-linklocal=no|unwanted|prefer|force + ; no : bind only to global ipv6 + ; unwanted (default) : prefer global address, then LL + ; prefer : prefer LL, then global + ; force : LL only + --bind-wait-ifup= ; wait for interface to appear and up + --bind-wait-ip= ; after ifup wait for ip address to appear up to N seconds + --bind-wait-ip-linklocal= ; accept only link locals first N seconds then any + --bind-wait-only ; wait for bind conditions satisfaction then exit. return code 0 if success. + --port= ; port number to listen on + --socks ; implement socks4/5 proxy instead of transparent proxy + --local-rcvbuf= ; SO_RCVBUF for local legs + --local-sndbuf= ; SO_SNDBUF for local legs + --remote-rcvbuf= ; SO_RCVBUF for remote legs + --remote-sndbuf= ; SO_SNDBUF for remote legs + --skip-nodelay ; do not set TCP_NODELAY for outgoing connections. incompatible with split. + --no-resolve ; disable socks5 remote dns + --maxconn= ; max number of local legs + --maxfiles= ; max file descriptors (setrlimit). min requirement is (X*connections+16), where X=6 in tcp proxy mode, X=4 in tampering mode. + ; its worth to make a reserve with 1.5 multiplier. by default maxfiles is (X*connections)*1.5+16 + --max-orphan-time= ; if local leg sends something and closes and remote leg is still connecting then cancel connection attempt after N seconds + + --hostlist= ; only act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) + --hostlist-exclude= ; do not act on hosts in the list (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed) + --split-http-req=method|host ; split http request at specified logical position. + --split-pos= ; split at specified pos. split-http-req takes precedence over split-pos for http reqs. + --split-any-protocol ; split not only http and https + --disorder ; when splitting simulate sending second fragment first + --hostcase ; change Host: => host: + --hostspell ; exact spelling of "Host" header. must be 4 chars. default is "host" + --hostdot ; add "." after Host: name + --hosttab ; add tab after Host: name + --hostnospace ; remove space after Host: + --hostpad= ; add dummy padding headers before Host: + --domcase ; mix domain case after Host: like this : TeSt.cOm + --methodspace ; add extra space after method + --methodeol ; add end-of-line before method + --unixeol ; replace 0D0A to 0A + --tlsrec=sni ; make 2 TLS records. split at SNI. don't split if SNI is not present. + --tlsrec-pos= ; make 2 TLS records. split at specified pos + --daemon ; daemonize + --pidfile= ; write pid to file + --user= ; drop root privs + --uid=uid[:gid] ; drop root privs +``` + +The manipulation parameters can be combined in any way. + +`split-http-req` takes precedence over split-pos for http reqs. + +split-pos works by default only on http and TLS ClientHello. use `--split-any-protocol` to act on any packet + +tpws can bind to multiple interfaces and IP addresses (up to 32). + +Port number is always the same. + +Parameters `--bind-iface*` and `--bind-addr` create new bind. + +Other parameters `--bind-*` are related to the last bind. + +link local ipv6 (`fe80::/8`) mode selection : + +``` +--bind-iface6 --bind-linklocal=no : first selects private address fc00::/7, then global address +--bind-iface6 --bind-linklocal=unwanted : first selects private address fc00::/7, then global address, then LL +--bind-iface6 --bind-linklocal=prefer : first selects LL, then private address fc00::/7, then global address +--bind-iface6 --bind-linklocal=force : select only LL +``` + +To bind to all ipv4 specify `--bind-addr "0.0.0.0"`, all ipv6 - `::`. + +`--bind-addr=""` - mean bind to all ipv4 and ipv6. + +If no binds are specified default bind to all ipv4 and ipv6 addresses is created. + +To bind to a specific link local address do : `--bind-iface6=fe80::aaaa:bbbb:cccc:dddd%iface-name` + +The `--bind-wait*` parameters can help in situations where you need to get IP from the interface, but it is not there yet, it is not raised +or not configured. + +In different systems, ifup events are caught in different ways and do not guarantee that the interface has already received an IP address of a certain type. + +In the general case, there is no single mechanism to hang oneself on an event of the type "link local address appeared on the X interface." + +To bind to a specific ip when its interface may not be configured yet do : `--bind-addr=192.168.5.3 --bind-wait-ip=20` + +It's possible to bind to any nonexistent address in transparent mode but in socks mode address must exist. + +In socks proxy mode no additional system privileges are required. Connections to local IPs of the system where tpws runs are prohibited. +tpws supports remote dns resolving (curl : `--socks5-hostname` firefox : `socks_remote_dns=true`) , but does it in blocking mode. + +tpws uses async sockets for all activity but resolving can break this model. + +if tpws serves many clients it can cause trouble. also DoS attack is possible against tpws. + +if remote resolving causes trouble configure clients to use local name resolution and use +`--no-resolve` option on tpws side. + +`--disorder` is an additional flag to any split option. +It tries to simulate `--disorder2` option of `nfqws` using standard socket API without the need of additional privileges. +This works fine in Linux and MacOS but unexpectedly in FreeBSD and OpenBSD +(system sends second fragment then the whole packet instead of the first fragment). + +`--tlsrec` and `--tlsrec-pos` allow to split TLS ClientHello into 2 TLS records in one TCP segment. +`--tlsrec=sni` splits between 1st and 2nd chars of the hostname. No split occurs if SNI is not present. +`--tlsrec-pos` splits at specified position. If TLS data block size is too small pos=1 is applied. +`--tlsrec` can be combined with `--split-pos` and `--disorder`. +`--tlsrec` breaks significant number of sites. Crypto libraries on end servers usually accept fine modified ClientHello +but middleboxes such as CDNs and ddos guards - not always. +Use of `--tlsrec` without filters is discouraged. + + +## Ways to get a list of blocked IP + +nftables can't work with ipsets. Native nf sets require lots of RAM to load large ip lists with subnets and intervals. +In case you're on a low RAM system and need large lists it may be required to fall back to iptables+ipset. + +1. Enter the blocked domains to `ipset/zapret-hosts-user.txt` and run `ipset/get_user.sh` +At the output, you get `ipset/zapret-ip-user.txt` with IP addresses. + +2. `ipset/get_reestr_*.sh`. Russian specific + +3. `ipset/get_antifilter_*.sh`. Russian specific + +4. `ipset/get_config.sh`. This script calls what is written into the GETLIST variable from the config file. + +If the variable is not defined, then only lists for ipsets nozapret/nozapret6 are resolved. + +So, if you're not russian, the only way for you is to manually add blocked domains. +Or write your own `ipset/get_iran_blocklist.sh` , if you know where to download this one. + +On routers, it is not recommended to call these scripts more than once in 2 days to minimize flash memory writes. + +`ipset/create_ipset.sh` executes forced ipset update. +With `no-update` parameter `create_ipset.sh` creates ipset but populate it only if it was actually created. + +It's useful when multiple subsequent calls are possible to avoid wasting of cpu time redoing the same job. + +Ipset loading is resource consuming. Its a good idea to call create_ipset without `no-update` parameter + +only once a several days. Use it with `no-update` option in other cases. + +ipset scripts automatically call ip2net utility. +ip2net helps to reduce ip list size by combining IPs to subnets. Also it cuts invalid IPs from the list. +Stored lists are already processed by ip2net. They are error free and ready for loading. + +`create_ipset.sh` supports loading ip lists from gzip files. First it looks for the filename with the ".gz" extension, +such as `zapret-ip.txt.gz`, if not found it falls back to the original name `zapret-ip.txt`. + +So your own get_iran_blockslist.sh can use "zz" function to produce gz. Study how other russian `get_XXX.sh` work. + +Gzipping helps saving a lot of precious flash space on embedded systems. + +User lists are not gzipped because they are not expected to be very large. + +You can add a list of domains to `ipset/zapret-hosts-user-ipban.txt`. Their ip addresses will be placed +in a separate ipset "ipban". It can be used to route connections to transparent proxy "redsocks" or VPN. + +IPV6: if ipv6 is enabled, then additional txt's are created with the same name, but with a "6" at the end before the extension. + +`zapret-ip.txt` => `zapret-ip6.txt` + +The ipsets zapret6 and ipban6 are created. + +IP EXCLUSION SYSTEM. All scripts resolve `zapret-hosts-user-exclude.txt` file, creating `zapret-ip-exclude.txt` and `zapret-ip-exclude6.txt`. + +They are the source for ipsets nozapret/nozapret6. All rules created by init scripts are created with these ipsets in mind. +The IPs placed in them are not involved in the process. +zapret-hosts-user-exclude.txt can contain domains, ipv4 and ipv6 addresses or subnets. + +FreeBSD. `ipset/*.sh` scripts also work in FreeBSD. Instead of ipset they create ipfw lookup tables with the same names as in Linux. +ipfw tables can store both ipv4 and ipv6 addresses and subnets. There's no 4 and 6 separation. + +LISTS_RELOAD config parameter defines a custom lists reloading command. +Its useful on BSD systems with PF. +LISTS_RELOAD=- disables reloading ip list backend. + +## Domain name filtering + +An alternative to ipset is to use tpws or nfqws with a list(s) of domains. +Both `tpws` and `nfqws` take any number of include (`--hostlist`) and exclude (`--hostlist-exclude`) domain lists. +All lists of the same type are combined internally leaving only 2 lists : include and exclude. + +Exclude list is checked first. Fooling is cancelled if domain belongs to exclude list. +If include list is present and domain does not belong to that list fooling is also cancelled. +Empty list means absent list. Otherwise fooling goes on. + +Launch system looks for 2 include lists : + +`ipset/zapret-hosts-users.txt.gz` or `ipset/zapret-hosts-users.txt` + +`ipset/zapret-hosts.txt.gz` or `ipset/zapret-hosts.txt` + +and 1 exclude list + +`ipset/zapret-hosts-users-exclude.txt.gz` or `ipset/zapret-hosts-users-exclude.txt` + +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" . + +tpws and nfqws reread lists on HUP signal. + +When filtering by domain name, daemons should run without filtering by ipset. +When using large regulator lists estimate the amount of RAM on the router ! + + +## Choosing parameters + +The file `/opt/zapret/config` is used by various components of the system and contains basic settings. +It needs to be viewed and edited if necessary. + +Which firewall type use on linux systems : `nftables` or `iptables`. +On traditional systems `nftables` is selected by default if `nft` is installed. +On openwrt by default `nftables` is selected on `firewall4` based systems. + +`FWTYPE=iptables` + +Main mode : + +``` +tpws - tpws transparent mode +tpws-socks - tpws socks mode + binds to localhost and LAN interface (if IFACE_LAN is specified or the system is OpenWRT). port 988 +nfqws - nfqws +filter - only fill ipset or load hostlist +custom - use custom script for running daemons and establishing firewall rules +``` + +`MODE=tpws` + +Enable http fooling : + +`MODE_HTTP=1` + +Apply fooling to keep alive http sessions. Only applicable to nfqws. Tpws always fool keepalives. +Not enabling this can save CPU time. + +`MODE_HTTP_KEEPALIVE=0` + +Enable https fooling : + +`MODE_HTTPS=1` + +Enable quic fooling : + +`MODE_QUIC=1` + +Host filtering mode : +``` +none - apply fooling to all hosts +ipset - limit fooling to hosts from ipset zapret/zapret6 +hostlist - limit fooling to hosts from hostlist +``` + +`MODE_FILTER=none` + +Its possible to change manipulation options used by tpws : + +`TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3"` + +nfqws options for DPI desync attack: + +``` +DESYNC_MARK=0x40000000 +NFQWS_OPT_DESYNC="--dpi-desync=fake --dpi-desync-ttl=0 --dpi-desync-fooling=badsum --dpi-desync-fwmark=$DESYNC_MARK" +``` + +Separate nfqws options for http and https and ip protocol versions 4,6: + +``` +NFQWS_OPT_DESYNC_HTTP="--dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" +NFQWS_OPT_DESYNC_HTTPS="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" +NFQWS_OPT_DESYNC_HTTP6="--dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" +NFQWS_OPT_DESYNC_HTTPS6="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" +``` + +If one of `NFQWS_OPT_DESYNC_HTTP`/`NFQWS_OPT_DESYNC_HTTPS` is not defined it takes value of NFQWS_OPT_DESYNC. +If one of `NFQWS_OPT_DESYNC_HTTP6`/`NFQWS_OPT_DESYNC_HTTPS6` is not defined it takes value from +`NFQWS_OPT_DESYNC_HTTP`/`NFQWS_OPT_DESYNC_HTTPS`. +It means if only `NFQWS_OPT_DESYNC` is defined all four take its value. + +If a variable is not defined, the value `NFQWS_OPT_DESYNC` is taken. + +Separate QUIC options for ip protocol versions : + +``` +NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake" +NFQWS_OPT_DESYNC_QUIC6="--dpi-desync=hopbyhop" +``` + +If `NFQWS_OPT_DESYNC_QUIC6` is not specified `NFQWS_OPT_DESYNC_QUIC` is taken. + + +flow offloading control (if supported) + +``` +donttouch : disable system flow offloading setting if selected mode is incompatible with it, dont touch it otherwise and dont configure selective flow offloading +none : always disable system flow offloading setting and dont configure selective flow offloading +software : always disable system flow offloading setting and configure selective software flow offloading +hardware : always disable system flow offloading setting and configure selective hardware flow offloading +``` + +`FLOWOFFLOAD=donttouch` + +The GETLIST parameter tells the install_easy.sh installer which script to call +to update the list of blocked ip or hosts. +Its called via `get_config.sh` from scheduled tasks (crontab or systemd timer). +Put here the name of the script that you will use to update the lists. +If not, then the parameter should be commented out. + +You can individually disable ipv4 or ipv6. If the parameter is commented out or not equal to "1", +use of the protocol is permitted. + +``` +#DISABLE_IPV4=1 +DISABLE_IPV6=1 +``` + +The number of threads for mdig multithreaded DNS resolver (1..100). +The more of them, the faster, but will your DNS server be offended by hammering ? + +`MDIG_THREADS=30` + +temp directory. Used by ipset/*.sh scripts for large lists processing. +/tmp by default. Can be reassigned if /tmp is tmpfs and RAM is low. +TMPDIR=/opt/zapret/tmp + +ipset and nfset options : + +``` +SET_MAXELEM=262144 +IPSET_OPT="hashsize 262144 maxelem 2097152 +``` + +Kernel automatically increases hashsize if ipset is too large for the current hashsize. +This procedure requires internal reallocation and may require additional memory. +On low RAM systems it can cause errors. +Do not use too high hashsize. This way you waste your RAM. And dont use too low hashsize to avoid reallocs. + +ip2net options. separate for ipv4 and ipv6. + +``` +IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4" +IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5" +``` + +Enable gzip compression for large lists. Used by ipset/*.sh scripts. + +`GZIP_LISTS=1` + +Command to reload ip/host lists after update. +Comment or leave empty for auto backend selection : ipset or ipfw if present. +On BSD systems with PF no auto reloading happens. You must provide your own command. +Newer FreeBSD versions support table only reloading : `pfctl -Tl -f /etc/pf.conf` +Set to "-" to disable reload. + +`LISTS_RELOAD="pfctl -f /etc/pf.conf"` + +In openwrt there's default network `lan`. Only traffic coming from this network is redirected to tpws by default. +To override this behaviour set the following variable : + +`OPENWRT_LAN="lan lan2 lan3"` + +The `INIT_APPLY_FW=1` parameter enables the init script to independently apply iptables rules. +With other values or if the parameter is commented out, the rules will not be applied. +This is useful if you have a firewall management system, in the settings of which you should tie the rules. +Not applicable to `OpenWRT` if used with `firewall3+iptables`. + +The following settings are not relevant for openwrt : + +If your system works as a router, then you need to enter the names of the internal and external interfaces: +``` +IFACE_LAN=eth0 +IFACE_WAN=eth1 +IFACE_WAN6="henet ipsec0" +``` +Multiple interfaces are space separated. IF IFACE_WAN6 is omitted then IFACE_WAN value is taken. + +IMPORTANT: configuring routing, masquerade, etc. not a zapret task. +Only modes that intercept transit traffic are enabled. +It's possible to specify multiple interfaces like this : `IFACE_LAN="eth0 eth1 eth2"` + + +## Screwing to the firewall control system or your launch system + +If you use some kind of firewall management system, then it may conflict with an existing startup script. +When re-applying the rules, it could break the iptables settings from the zapret. +In this case, the rules for iptables should be screwed to your firewall separately from running tpws or nfqws. + +The following calls allow you to apply or remove iptables rules separately: + +``` + /opt/zapret/init.d/sysv/zapret start_fw + /opt/zapret/init.d/sysv/zapret stop_fw + /opt/zapret/init.d/sysv/zapret restart_fw +``` + +And you can start or stop the demons separately from the firewall: + +``` + /opt/zapret/init.d/sysv/zapret start_daemons + /opt/zapret/init.d/sysv/zapret stop_daemons + /opt/zapret/init.d/sysv/zapret restart_daemons +``` + +nftables nearly eliminate conflicts betweeen firewall control systems because they allow +separate tables and netfilter hooks. `zapret` nf table is used for zapret purposes. +If your system does not touch it everything will likely be OK. + +Some additional nftables-only calls exist : + +Lookup `lanif`, `wanif`, `wanif6` and `flow table` interface sets. +``` + /opt/zapret/init.d/sysv/zapret list_ifsets +``` + +Renew `lanif`, `wanif`, `wanif6` and `flow table` interface sets. +Taken from `IFACE_LAN`, `IFACE_WAN` config variables on traditional Linux systems. +Autoselected on `OpenWRT`. `lanif` can be extended using `OPENWRT_LAN` config variable. +``` + /opt/zapret/init.d/sysv/zapret reload_ifsets +``` + +Calls `nft -t list table inet zapret`. +``` + /opt/zapret/init.d/sysv/zapret list_table +``` + +It's also possible to hook with your script to any stage of zapret firewall processing. +The following settings are available in the zapret config file : + +``` +INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up" +INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up" +INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down" +INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down" +``` + +Hooks are extremely useful if you need nftables sets populated by zapret scripts. +nfsets can only belong to one table. You have to write rule there and synchorize them with zapret scripts. + +## Installation + +### Checking ISP + +Before running zapret you must discover working bypass strategy. +`blockcheck.sh` automates this process. It first checks DNS then tries many strategies finding the working ones. +Note that DNS check is mostly Russia targeted. It checks several pre-defined blocked in Russia domains and +verifies system DNS answers with public DNS answers. Because ISP can block public DNS or redirect any DNS queries +to their servers `blockcheck.sh` also checks that all returned answers are unique. Usually if DNS is blocked +ISP returns single ip for all blocked domains to redirect you to their "access denied" page. +`blockcheck.sh` works in Linux and FreeBSD. + +### desktop linux system + +Simple install works on most modern linux distributions with systemd or openrc, OpenWRT and MacOS. +Run `install_easy.sh` and answer its questions. + +### OpenWRT + +`install_easy.sh` works on openwrt but there're additional challenges. +They are mainly about possibly low flash free space. +Simple install will not work if it has no space to install itself and required packages from the repo. + +Another challenge would be to bring zapret to the router. You can download zip from github and use it. +Do not repack zip contents in Windows, because this way you break chmod and links. +Install openssh-sftp-server and unzip to openwrt and use sftp to transfer the file. + +The best way to start is to put zapret dir to `/tmp` and run `/tmp/zapret/install_easy.sh` from there. +After installation remove `/tmp/zapret` to free RAM. + +The absolute minimum for openwrt is 64/8 system, 64/16 is comfortable, 128/extroot is recommended. + +### Android + +Its not possible to use nfqws and tpws in transparent proxy mode without root privileges. +Without root tpws can run in --socks mode. + +Android has NFQUEUE and nfqws should work. + +There's no ipset support unless you run custom kernel. In common case task of bringing up ipset +on android is ranging from "not easy" to "almost impossible", unless you find working kernel +image for your device. + +Android does not use /etc/passwd, `tpws --user` won't work. There's replacement. +Use numeric uids in `--uid` option. +Its recommended to use gid 3003 (AID_INET), otherwise tpws will not have inet access. + +Example : `--uid 1:3003` + +In iptables use : `! --uid-owner 1` instead of `! --uid-owner tpws`. + +Nfqws should be executed with `--uid 1`. Otherwise on some devices or firmwares kernel may partially hang. Looks like processes with certain uids can be suspended. With buggy chineese cellular interface driver this can lead to device hang. + +Write your own shell script with iptables and tpws, run it using your root manager. +Autorun scripts are here : + +magisk : `/data/adb/service.d` + +supersu : `/system/su.d` + +How to run tpws on root-less android. +You can't write to `/system`, `/data`, can't run from sd card. +Selinux prevents running executables in `/data/local/tmp` from apps. +Use adb and adb shell. + +``` +mkdir /data/local/tmp/zapret +adb push tpws /data/local/tmp/zapret +chmod 755 /data/local/tmp/zapret /data/local/tmp/zapret/tpws +chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws +``` + +Now its possible to run `/data/local/tmp/zapret/tpws` from any app such as tasker. + +### FreeBSD, OpenBSD, MacOS + +see docs/bsd.eng.md + +### Windows (WSL) + +Using WSL (Windows subsystem for Linux) it's possible to run tpws in socks mode under rather new builds of +windows 10 and windows server. +Its not required to install any linux distributions as suggested in most articles. +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. +Run : `wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz` + +Run tpws : `wsl --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 ` + +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). + +NOTICE. There is native windows solution GoodByeDPI. It works on packet level like nfqws. + +### Other devices + +Author's goal does not include easy supporting as much devices as possibles. +Please do not ask for easy supporting firmwares. It requires a lot of work and owning lots of devices. Its counterproductive. +As a devices owner its easier for you and should not be too hard if firmware is open. +Most closed stock firmwares are not designed for custom usage and sometimes actively prevent it. +In the latter case you have to hack into it and reverse engineer. Its not easy. +Binaries are universal. They can run on almost all firmwares. +You will need : + * root shell access. true sh shell, not microtik-like console + * startup hook + * r/w partition to store binaries and startup script with executable permission (+x) + * tpws can be run almost anywhere but nfqws require kernel support for NFQUEUE. Its missing in most firmwares. + * too old 2.6 kernels are unsupported and can cause errors. newer 2.6 kernels are OK. +If binaries crash with segfault (rare but happens on some kernels) try to unpack upx like this : upx -d tpws. + +First manually debug your scenario. Run iptables + daemon and check if its what you want. +Write your own script with iptables magic and run required daemon from there. Put it to startup. +Dont ask me how to do it. Its different for all firmwares and requires studying. +Find manual or reverse engineer yourself. +Check for race conditions. Firmware can clear or modify iptables after your startup script. +If this is the case then run another script in background and add some delay there. diff --git a/docs/readme.txt b/docs/readme.txt index 8ad0f47..c1401cd 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -1,1436 +1,1451 @@ -zapret v.50 - -English -------- - -For english version refer to docs/readme.eng.txt - -Для чего это надо ------------------ - -Автономное, без задействования сторонних серверов, средство противодействия DPI. -Может помочь обойти блокировки или замедление сайтов http(s), сигнатурный анализ tcp и udp протоколов, -например с целью блокировки VPN. - -Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под openwrt. -Поддерживаются традиционные Linux системы, FreeBSD, OpenBSD, частично MacOS. -В некоторых случаях возможна самостоятельная прикрутка решения к различным прошивкам. - -Как побыстрее начать --------------------- - -Читайте docs/quick_start.txt - - -Как это работает ----------------- - -В самом простейшем случае вы имеете дело с пассивным DPI. Пассивный DPI может читать трафик -из потока, может инжектить свои пакеты, но не может блокировать проходящие пакеты. -Если запрос "плохой", пассивный DPI инжектит пакет RST, опционально дополняя его пакетом http redirect. -Если фейк пакет инжектится только для клиента, в этом случае можно обойтись командами iptables -для дропа RST и/или редиректа на заглушку по определенным условиям, которые нужно подбирать -для каждого провайдера индивидуально. Так мы обходим последствия срабатывания триггера запрета. -Если пассивный DPI направляет пакет RST в том числе и серверу, то вы ничего с этим не сможете сделать. -Ваша задача - не допустить срабатывания триггера запрета. Одними iptables уже не обойдетесь. -Этот проект нацелен именно на предотвращение срабатывания запрета, а не ликвидацию его последствий. - -Активный DPI ставится в разрез провода и может дропать пакеты по любым критериям, -в том числе распознавать TCP потоки и блокировать любые пакеты, принадлежащие потоку. - -Как не допустить срабатывания триггера запрета ? Послать то, на что DPI не расчитывает -и что ломает ему алгоритм распознавания запросов и их блокировки. - -Некоторые DPI не могут распознать http запрос, если он разделен на TCP сегменты. -Например, запрос вида "GET / HTTP/1.1\r\nHost: kinozal.tv......" -мы посылаем 2 частями : сначала идет "GET ", затем "/ HTTP/1.1\r\nHost: kinozal.tv.....". -Другие DPI спотыкаются, когда заголовок "Host:" пишется в другом регистре : например, "host:". -Кое-где работает добавление дополнительного пробела после метода : "GET /" => "GET /" -или добавление точки в конце имени хоста : "Host: kinozal.tv." - -Существует и более продвинутая магия, направленная на преодоление DPI на пакетном уровне. - -Подробнее про DPI : - https://habr.com/ru/post/335436 - https://geneva.cs.umd.edu/papers/geneva_ccs19.pdf - -Как это реализовать на практике в системе linux ------------------------------------------------ - -Если кратко, то варианты можно классифицировать по следующей схеме : - -1) Пассивный DPI, не отправляющий RST серверу. Помогут индивидуально настраиваемые под провайдера команды iptables. -На rutracker в разделе "обход блокировок - другие способы" по этому вопросу существует отдельная тема. -В данном проекте не рассматривается. Если вы не допустите срабатывание триггера запрета, то и не придется -бороться с его последствиями. -2) Модификация TCP соединения на уровне потока. Реализуется через proxy или transparent proxy. -3) Модификация TCP соединения на уровне пакетов. Реализуется через обработчик очереди NFQUEUE и raw сокеты. - -Для вариантов 2 и 3 реализованы программы tpws и nfqws соответственно. -Чтобы они работали, необходимо их запустить с нужными параметрами и перенаправить на них определенный трафик -средствами iptables или nftables. - - -Для перенаправления tcp соединения на transparent proxy используются команды следующего вида : - -проходящий трафик : -iptables -t nat -I PREROUTING -i <внутренний_интерфейс> -p tcp --dport 80 -j DNAT --to 127.0.0.127:988 -исходящий трафик : -iptables -t nat -I OUTPUT -o <внешний_интерфейс> -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988 - -DNAT на localhost работает в цепочке OUTPUT, но не работает в цепочке PREROUTING без включения параметра route_localnet : - -sysctl -w net.ipv4.conf.<внутренний_интерфейс>.route_localnet=1 - -Можно использовать "-j REDIRECT --to-port 988" вместо DNAT , однако в этом случае процесс transparent proxy -должен слушать на ip адресе входящего интерфейса или на всех адресах. Слушать на всех - не есть хорошо -с точки зрения безопасности. Слушать на одном (локальном) можно, но в случае автоматизированного -скрипта придется его узнавать, потом динамически вписывать в команду. В любом случае требуются дополнительные усилия. -Использование route_localnet тоже имеет потенциальные проблемы с безопасностью. Вы делаете доступным все, что висит -на 127.0.0.0/8 для локальной подсети <внутренний_интерфейс>. Службы обычно привязываются к 127.0.0.1, поэтому можно -средствами iptables запретить входящие на 127.0.0.1 не с интерфейса lo, либо повесить tpws на любой другой IP из -из 127.0.0.0/8, например на 127.0.0.127, и разрешить входящие не с lo только на этот IP. - -iptables -A INPUT ! -i lo -d 127.0.0.127 -j ACCEPT -iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j DROP - -Фильтр по owner необходим для исключения рекурсивного перенаправления соединений от самого tpws. -tpws запускается под пользователем "tpws", для него задается исключающее правило. - -tpws может использоваться в режиме socks proxy. В этом случае iptables не нужны, а нужно прописать socks -в настройки программы (например, броузера), с которой будем обходить блокировки. -transparent proxy отличается от socks именно тем, что в варианте transparent настраивать клиентские программы не нужно. - - -Для перенаправления на очередь NFQUEUE исходящего и проходящего в сторону внешнего интерфейса трафика используются -команды следующего вида : - -iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -j NFQUEUE --queue-num 200 --queue-bypass - - -Чтобы не трогать трафик на незаблокированные адреса, можно взять список заблокированных хостов, заресолвить его -в IP адреса и загнать в ipset zapret, затем добавить фильтр в команду : - -iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass - -DPI может ловить только первый http запрос, игнорируя последующие запросы в keep-alive сессии. -Тогда можем уменьшить нагрузку на проц, отказавшись от процессинга ненужных пакетов. - -iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass - -Фильтр по mark нужен для отсечения от очереди пакетов, сгенерированных внутри nfqws. -Если применяется фильтр по connbytes 1:4, то обязательно добавлять в iptables и фильтр по mark. Иначе возможно -перепутывание порядка следования пакетов, что приведет к неработоспособности метода. - - -Если ваше устройство поддерживает аппаратное ускорение (flow offloading, hardware nat, hardware acceleration), то iptables могут не работать. -При включенном offloading пакет не проходит по обычному пути netfilter. -Необходимо или его отключить, или выборочно им управлять. - -В новых ядрах (и в более старых, openwrt портировал изменение на 4.14) присутствует software flow offloading (SFO). -Пакеты, проходящие через SFO, так же проходят мимо большей части механизмов iptables. -При включенном SFO работает DNAT/REDIRECT (tpws). Эти соединения исключаются из offloading. -Однако, остальные соединения идут через SFO, потому NFQUEUE будет срабатывать только до помещения -соединения в flowtable. Практически это означает, что nfqws будет работать на window size changing, -но не будут работать опции по модификации содержимого пакетов. -Offload включается через специальный target в iptables "FLOWOFFLOAD". Не обязательно пропускать весь трафик через offload. -Можно исключить из offload соединения, которые должны попасть на tpws или nfqws. -openwrt не предусматривает выборочного управления offload. -Поэтому скрипты zapret поддерживают свою систему выборочного управления offload в openwrt. - - -Особенности применения ip6tables --------------------------------- - -ip6tables работают почти точно так же, как и ipv4, но есть ряд важных нюансов. -В DNAT следует брать адрес --to в квадратные скобки. Например : - - ip6tables -t nat -I OUTPUT -o <внешний_интерфейс> -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to [::1]:988 - -Параметра route_localnet не существует для ipv6. -DNAT на localhost (::1) возможен только в цепочке OUTPUT. -В цепочке PREROUTING DNAT возможен на любой global address или на link local address того же интерфейса, -откуда пришел пакет. -NFQUEUE работает без изменений. - - -Особенности применения nftables -------------------------------- - -Более подробно преимущества и недостатки nftables применительно к данной системе описаны в docs/nftables_notes.txt -Если коротко, то в nftables невозможно работать с большими ip листами на системах с малым количеством RAM. -Остальные рассматриваемые здесь функции могут быть перенесены на nftables. - -Рекомендуется версия nft 1.0.2 или выше. - -Относительно старые версии ядра и/или утилиты nft могут вызывать ошибки. -В частности, на ubuntu 18.04 с ядром 4.15 будут проблемы. В 20.04 - работает. - - -Когда это работать не будет ---------------------------- - -* Если подменяется DNS. С этой проблемой легко справиться. -* Если блокировка осуществляется по IP. -* Если соединение проходит через фильтр, способный реконструировать TCP соединение, и который -следует всем стандартам. Например, нас заворачивают на squid. Соединение идет через полноценный стек tcpip -операционной системы, фрагментация отпадает сразу как средство обхода. Squid правильный, он все найдет -как надо, обманывать его бесполезно. -НО. Заворачивать на squid могут позволить себе лишь небольшие провайдеры, поскольку это очень ресурсоемко. -Большие компании обычно используют DPI, который расчитан на гораздо большую пропускную способность. -Может применяться комбинированный подход, когда на DPI заворачивают только IP из "плохого" списка, -и дальше уже DPI решает пропускать или нет. Так можно снизить нагрузку на DPI в десятки, если не сотни раз, -а следовательно не покупать очень дорогие решения, обойдясь чем-то существенно более дешевым. -Мелкие провайдеры могут покупать услугу фильтрации у вышестоящих, чтобы самим не морочиться, и -они уже будут применять DPI. - - -nfqws ------ - -Эта программа - модификатор пакетов и обработчик очереди NFQUEUE. -Для BSD систем существует адаптированный вариант - dvtws, собираемый из тех же исходников (см. bsd.txt). - - --debug=0|1 ; 1=выводить отладочные сообщения - --daemon ; демонизировать прогу - --pidfile= ; сохранить PID в файл - --user= ; менять uid процесса - --uid=uid[:gid] ; менять uid процесса - --qnum=N ; номер очереди N - --bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов - --bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов - --wsize=[:] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !) - --wssize=[:] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !) - --wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N - --ctrack-timeouts=S:E:F[:U] ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60 - --hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:". - --hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета - --hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase - --domcase ; домен после Host: сделать таким : TeSt.cOm - --dpi-desync=[,][, ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000 - --dpi-desync-ttl= ; установить ttl для десинхронизирующих пакетов - --dpi-desync-ttl6= ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl - --dpi-desync-fooling= ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum hopbyhop hopbyhop2 - --dpi-desync-retrans=0|1 ; (только для fake,rst,rstack) 0(default)=отправлять оригинал следом за фейком 1=дропать оригинал, заставляя ОС выполнять ретрансмиссию через 0.2 сек - --dpi-desync-repeats= ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты) - --dpi-desync-skip-nosni=0| 1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI - --dpi-desync-split-pos=<1..1500> ; (только для split*, disorder*) разбивать пакет на указанной позиции - --dpi-desync-badseq-increment= ; инкремент sequence number для badseq. по умолчанию -10000 - --dpi-desync-badack-increment= ; инкремент ack sequence number для badseq. по умолчанию -66000 - --dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных - --dpi-desync-fake-http=|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному w3.org - --dpi-desync-fake-tls=|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному w3.org - --dpi-desync-fake-unknown=|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт - --dpi-desync-fake-quic=|0xHEX ; файл, содержащий фейковый QUIC Initial - --dpi-desync-fake-dht=|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт - --dpi-desync-fake-unknown-udp=|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт - --dpi-desync-udplen-increment= ; насколько увеличивать длину udp пейлоада в режиме udplen - --dpi-desync-udplen-pattern=|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули - --dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N - --hostlist= ; применять дурение только к хостам из листа. может быть множество листов, они обьединяются. пустой обший лист = его отсутствие - --hostlist-exclude= ; не применять дурение к хостам из листа. может быть множество листов, они обьединяются - -Параметры манипуляции могут сочетаться в любых комбинациях. - -ЗАМЕЧАНИЕ. Параметр --wsize считается устаревшим и более не поддерживается в скриптах. -Функции сплита выполняются в рамках атаки десинхронизации. Это быстрее и избавляет от целого ряда недостатков wsize. - -АТАКА ДЕСИНХРОНИЗАЦИИ DPI -Суть ее в следующем. После выполнения tcp 3-way handshake идет первый пакет с данными от клиента. -Там обычно "GET / ..." или TLS ClientHello. Мы дропаем этот пакет, заменяя чем-то другим. -Это может быть поддельная версия с безобидным, но валидным запросом http или https (вариант fake), -пакет сброса соединения (варианты rst, rstack), разбитый на части оригинальный пакет с перепутанным -порядком следования сегментов + обрамление первого сегмента фейками (disorder), -то же самое без перепутывания порядка сегментов (split). -fakeknown отличается от fake тем, что применяется только к распознанному протоколу. -В литературе такие атаки еще называют TCB desynchronization и TCB teardown. -Надо, чтобы фейковые пакеты дошли до DPI, но не дошли до сервера. -На вооружении есть следующие возможности : установить низкий TTL, посылать пакет с инвалидной чексуммой, -добавлять tcp option "MD5 signature", испортить sequence numbers. Все они не лишены недостатков. - -* md5sig работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux. -* badsum не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой. - Наиболее распространенная настройка NAT роутера в Linux их не пропускает. На Linux построено большинство - домашних роутеров. Непропускание обеспечивается так : настройка ядра sysctl по умолчанию - net.netfilter.nf_conntrack_checksum=1 заставляет conntrack проверять tcp и udp чексуммы входящих пакетов - и выставлять state INVALID для пакетов с инвалидной суммой. - Обычно в правилах iptables вставляется правило для дропа пакетов с состоянием INVALID в цепочке FORWARD. - Совместное сочетание этих факторов приводит к непрохождению badsum через такой роутер. - В openwrt из коробки net.netfilter.nf_conntrack_checksum=0, в других роутерах часто нет, - и не всегда это можно изменить. Чтобы nfqws мог работать через роутер, нужно на нем выставить указанное - значение sysctl в 0. nfqws на самом роутере будет работать и без этой настройки, потому что - чексумма локально созданных пакетов не проверяется никогда. - Если роутер за другим NAT, например провайдерским, и он не пропускает invalid packets - вы ничего не сможете с этим сделать. Но обычно провайдеры все же пропускают badsum. - На некоторых адаптерах/свитчах/драйверах принудительно включен rx-checksum offload, badsum пакеты отсекаются - еще до получения в ОС. В этом случае если что-то и можно сделать, то только модифицировать драйвер, - что представляется задачей крайне нетривиальной. Установлено, что так себя ведут некоторые роутеры на базе mediatek. - badsum пакеты уходят с клиентской ОС, но роутером не видятся в br-lan через tcpdump. - При этом если nfqws выполняется на самом роутере, обход может работать. badsum нормально уходят с внешнего интерфейса. -* Пакеты с badseq будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется - на sequence numbers. По умолчанию смещение seq выбирается -10000. Практика показала, что некоторые DPI - не пропускают seq вне определенного окна. Однако, такое небольшое смещение может вызвать проблемы - при существенной потоковой передаче и потере пакетов. Если вы используете --dpi-desync-any-protocol, - может понадобится установить badseq increment 0x80000000. Это обеспечит надежную гарантию, - что поддельный пакет не вклинится в tcp window на сервере. Так же было замечено, что badseq ломает логику - некоторых DPI при анализе http, вызывая зависание соединения. Причем на тех же DPI TLS с badseq работает нормально. -* TTL казалось бы - лучший вариант, но он требует индивидуальной настройки под каждого провайдера. - Если DPI находится дальше локальных сайтов провайдера, то вы можете отрезать себе доступ к ним. - Необходим ip exclude list, заполняемый вручную. Вместе с ttl можно применять md5sig. Это ничего не испортит, - зато дает неплохой шанс работы сайтов, до которых "плохой" пакет дойдет по TTL. - Если не удается найти автоматическое решение, воспользуйтесь файлом zapret-hosts-user-exclude.txt. - Некоторые стоковые прошивки роутеров фиксируют исходящий TTL, без отключения этой опции через них работать не будет. - КАКИМ СТОИТ ВЫБИРАТЬ TTL : найдите минимальное значение, при котором обход еще работает. - Это и будет номер хопа вашего DPI. -* hopbyhop относится только к ipv6. Добавляется ipv6 extenstion header "hop-by-hop options". - В варианте hopbyhop2 добавляются 2 хедера, что является нарушением стандарта и гарантированно отбрасывается - стеком протоколов во всех ОС. Один хедер hop-by-hop принимается всеми ОС, однако на некоторых каналах/провайдерах - такие пакеты могут фильтроваться и не доходить. Расчет идет на то, что DPI проанализирует пакет с hop-by-hop, - но он либо не дойдет до адресата всилу фильтров провайдера, либо будет отброшен сервером, потому что хедера два. - -Режимы дурения могут сочетаться в любых комбинациях. --dpi-desync-fooling берет множество значений через запятую. - -Для режимов fake, rst, rstack после фейка отправляем оригинальный пакет. Можно его отправить сразу следом за фейком, а можно его просто дропнуть. -Если его дропнуть, ОС выполнит ретрансмиссию. Первая ретрансмиссия случается через 0.2 сек, потом задержка увеличивается экспоненциально. -Задержка может дать надежную гарантию, что пакеты пойдут именно в нужном порядке и будут именно в нем обработаны на DPI. -По умолчанию используется первый вариант, т.к. он быстрее. -При использовании dpi-desync-retrans=1 обязательно вставлять ограничитель connbytes в iptables, иначе получим зацикливание. - -Режим disorder делит оригинальный пакет на 2 части и отправляет следующую комбинацию в указанном порядке : -1. 2-я часть пакета -2. поддельная 1-я часть пакета, поле данных заполнено нулями -3. 1-я часть пакета -4. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз. -Оригинальный пакет дропается всегда. Параметр --dpi-desync-split-pos позволяет указать байтовую позицию, на которой -происходит разбивка. По умолчанию - 2. Если позиция больше длины пакета, позиция выбирается 1. -Этой последовательностью для DPI максимально усложняется задача реконструкции начального сообщения, -по которому принимается решение о блокировке. Некоторым DPI хватит и tcp сегментов в неправильном порядке, -поддельные части сделаны для дополнительной надежности и более сложных алгоритмов реконструкции. -Режим disorder2 отключает отправку поддельных частей. - -Режим split очень похож на disorder, только нет изменения порядка следования сегментов : -1. поддельная 1-я часть пакета, поле данных заполнено нулями -2. 1-я часть пакета -3. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз. -4. 2-я часть пакета -Режим split2 отключает отправку поддельных частей. -Он может быть использован как более быстрая альтернатива --wsize. - -disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны. - -Режимы десинхронизации hopbyhop, destopt и ipfrag1 (не путать с fooling !) относятся только к ipv6 и заключается -в добавлении хедера "hop-by-hop options" , "destination options" или "fragment" во все пакеты, попадающие под десинхронизацию. -Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено -к пакетам максимального размера. Это имеет место при передаче больших сообщений. -В случае невозможности отослать пакет дурение будет отменено, пакет будет выслан в оригинале. -Расчет идет на то, что DPI увидит 0 в поле next header основного заголовка ipv6 и не будет скакать по -extension хедерам в поисках транспортного хедера. Таким образом не поймет, что это tcp или udp, и пропустит пакет -без анализа. Возможно, какие-то DPI на это купятся. -Может сочетаться с любыми режимами 2-й фазы, кроме варианта "ipfrag1+ipfrag2". -Например, "hopbyhop,split2" означает разбить tcp пакет на 2 сегмента, в каждый из них добавить hop-by-hop. -При "hopbyhop,ipfrag2" последовательность хедеров будет : ipv6,hop-by-hop,fragment,tcp/udp. -Режим "ipfrag1" может срабатывать не всегда без специальной подготовки. См. раздел "IP фрагментация". - -Есть DPI, которые анализируют ответы от сервера, в частности сертификат из ServerHello, где прописаны домены. -Подтверждением доставки ClientHello является ACK пакет от сервера с номером ACK sequence, соответствующим длине ClientHello+1. -В варианте disorder обычно приходит сперва частичное подтверждение (SACK), потом полный ACK. -Если вместо ACK или SACK идет RST пакет с минимальной задержкой, то DPI вас отсекает еще на этапе вашего запроса. -Если RST идет после полного ACK спустя задержку, равную примерно пингу до сервера, -тогда вероятно DPI реагирует на ответ сервера. -DPI может отстать от потока, если ClientHello его удовлетворил и не проверять ServerHello. -Тогда вам повезло. Вариант fake может сработать. -Если же он не отстает и упорно проверяет ServerHello, то можно попробовать заставить сервер высылать ServerHello частями -через параметр --wssize (см. conntrack). -Если и это не помогает, то сделать с этим что-либо вряд ли возможно без помощи со стороны сервера. -Лучшее решение - включить на сервере поддержку TLS 1.3. В нем сертификат сервера передается в зашифрованном виде. -Это рекомендация ко всем админам блокируемых сайтов. Включайте TLS 1.3. Так вы дадите больше возможностей преодолеть DPI. - -Хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello. -Субдомены учитываются автоматически. Поддерживаются листы gzip. - -iptables для задействования атаки на первый пакет данных : - -iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass - -Этот вариант применяем, когда DPI не следит за всеми запросами http внутри keep-alive сессии. -Если следит, направляем только первый пакет от https и все пакеты от http : - -iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass -iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass - -mark нужен, чтобы сгенерированный поддельный пакет не попал опять к нам на обработку. nfqws выставляет fwmark при его отсылке. -хотя nfqws способен самостоятельно различать помеченные пакеты, фильтр в iptables по mark нужен при использовании connbytes, -чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный. -Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно. -Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею. -При отсутствии ограничения на connbytes, атака будет работать и без фильтра по mark. -Но лучше его все же оставить для увеличения скорости. - -Почему --connbytes 1:4 : -1 - для работы методов десинхронизации 0-й фазы и wssize -2 - иногда данные идут в 3-м пакете 3-way handshake -3 - стандартная ситуация -4 - для надежности. на случай, если выполнялась одна ретрансмиссия - -КОМБИНИРОВАНИЕ МЕТОДОВ ДЕСИНХРОНИЗАЦИИ -В параметре dpi-desync можно указать до 3 режимов через запятую. -0 фаза предполагает работу на этапе установления соединения. Может быть synack. -На 0 фазу не действует фильтр по hostlist. -Последующие режимы отрабатывают на пакетах с данными. -Режим 1-й фазы может быть fake,rst,rstack. Режим 2-й фазы может быть disorder,disorder2,split,split2,ipfrag2. -Может быть полезно, когда у провайдера стоит не один DPI. - -РЕЖИМ SYNACK -В документации по geneva это называется "TCB turnaround". Попытка ввести DPI в заблуждение относительно -ролей клиента и сервера. -!!! Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством -и DPI нет NAT. Атака не сработает через NAT роутер, но может сработать с него. -Для реализации атаки в linux обязательно требуется отключить стандартное правило firewall, -дропающее инвалидные пакеты в цепочке OUTPUT. Например : -A OUTPUT -m state --state INVALID -j DROP -В openwrt можно отключить drop INVALID в OUTPUT и FORWARD через опцию в /etc/config/firewall : - -config zone - option name 'wan' - ......... - option masq_allow_invalid '1' - -К сожалению, отключить только в OUTPUT таким образом нельзя. Но можно сделать иначе. Вписать в /etc/firewall.user : - -iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT -ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT - -Лучше делать так, потому что отсутствие дропа INVALID в FORWARD может привести к нежелательным утечкам пакетов из LAN. -Если не принять эти меры, отсылка SYN,ACK сегмента вызовет ошибку и операция будет прервана. -Остальные режимы тоже не сработают. Если поймете, что вам synack не нужен, обязательно верните правило дропа INVALID. - -ВИРТУАЛЬНЫЕ МАШИНЫ -Изнутри VM от virtualbox и vmware в режиме NAT не работают многие техники пакетной магии nfqws. -Принудительно заменяется ttl, не проходят фейк пакеты. Необходимо настроить сеть в режиме bridge. - -CONNTRACK -nfqws оснащен ограниченной реализацией слежения за состоянием tcp соединений (conntrack). -Он включается для реализации некоторых методов противодействия DPI. -На текущий момент это параметры --wssize и --dpi-desync-cutoff. -conntrack способен следить за фазой соединения : SYN,ESTABLISHED,FIN , количеством пакетов в каждую сторону, -sequence numbers. conntrack способен "кормиться" пакетами в обе или только в одну сторону. -Соединение попадает в таблицу при обнаружении пакетов с выставленными флагами SYN или SYN,ACK. -Поэтому если необходим conntrack, в правилах перенаправления iptables соединение должно идти на nfqws с самого первого -пакета, хотя затем может обрываться по фильтру connbytes. -Для UDP инициатором попадания в таблицу является первый UDP пакет. Он же и определяет направление потока. -Считается, что первый UDP пакет исходит от клиента к серверу. Далее все пакеты с совпадающими -src_ip,src_port,dst_ip,dst_port считаются принадлежащими этому потоку до истечения времени неактивности. -conntrack - простенький, он не писался с учетом всевозможных атак на соединение, он не проверяет -пакеты на валидность sequence numbers или чексумму. Его задача - лишь обслуживание нужд nfqws, он обычно -кормится только исходящим трафиком, потому нечувствителен к подменам со стороны внешней сети. -Соединение удаляется из таблицы, как только отпадает нужда в слежении за ним или по таймауту неактивности. -Существуют отдельные таймауты на каждую фазу соединения. Они могут быть изменены параметром --ctrack-timeouts. - ---wssize позволяет изменить с клиента размер tcp window для сервера, чтобы он послал следующие ответы разбитыми на части. -Чтобы это подействовало на все серверные ОС, необходимо менять window size в каждом исходящем с клиента пакете до отсылки сообщения, -ответ на который должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы -знать когда надо остановиться. Если не остановиться и все время устанавливать низкий wssize, скорость упадет катастрофически. -В linux это может быть купировано через connbytes, но в BSD системах такой возможности нет. -В случае http(s) останавливаемся сразу после отсылки первого http запроса или TLS ClientHello. -Если вы имеете дело с не http(s), то вам потребуется параметр --wssize-cutoff. Он устанавливает предел, с которого действие -wssize прекращается. Префикс d перед номером означает учитывать только пакеты с data payload, префикс s - relative sequence number, -проще говоря количество переданных клиентом байтов + 1. -Если проскочит пакет с http request или TLS ClientHello, действие wssize прекращается сразу же, не дожидаясь wssize-cutoff. -Если ваш протокол склонен к долгому бездействию, следует увеличить таймаут фазы ESTABLISHED через параметр --ctrack-timeouts. -Таймаут по умолчанию низкий - всего 5 минут. -Не забывайте, что nfqws кормится приходящими на него пакетами. Если вы ограничили поступление пакетов через connbytes, -то в таблице могут остаться повисшие соединения в фазе ESTABLISHED, которые отвалятся только по таймауту. -Для диагностики состояния conntrack пошлите сигнал SIGUSR1 процессу nfqws : killall -SIGUSR1 nfqws. -Текущая таблица будет выведена nfqws в stdout. - -Обычно в SYN пакете клиент отсылает кроме window size еще и TCP extension "scaling factor". -scaling factor представляет из себя степень двойки, на которую умножается window size : 0=>1, 1=>2, 2=>4, ..., 8=>256, ... -В параметре wssize scaling factor указывается через двоеточие. -Scaling factor может только снижаться, увеличение заблокировано, чтобы не допустить превышение размера окна со стороны сервера. -Для принуждения сервера к фрагментации ServerHello, чтобы избежать просекание имени сервера из сертификата сервера на DPI, -лучше всего использовать --wssize=1:6 . Основное правило - делать scale_factor как можно больше, чтобы после восстановления -window size итоговый размер окна стал максимально возможным. Если вы сделаете 64:0, будет очень медленно. -С другой стороны нельзя допустить, чтобы ответ сервера стал достаточно большим, чтобы DPI нашел там искомое. - -На --wssize не влияет фильтр hostlist, поскольку он действует с самого начала соединения, когда еще нельзя -принять решение о попадании в лист. ---wssize может замедлять скорость и/или увеличивать время ответа сайтов, поэтому если есть другие работающие способы -обхода DPI, лучше применять их. - ---dpi-desync-cutoff позволяет задать предел, при достижении которого прекращается применение dpi-desync. -Доступны префиксы n,d,s по аналогии с --wssize-cutoff. -Полезно совместно с --dpi-desync-any-protocol=1. -На склонных к бездействию соединениях следует изменить таймауты conntrack. -Если соединение выпало из conntrack и задана опция --dpi-desync-cutoff, dpi desync применяться не будет. - -ПОДДЕРЖКА UDP -Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip. -Для UDP действуют только режимы десинхронизации fake,hopbyhop,destopt,ipfrag1,ipfrag2,udplen,tamper. -Возможно сочетание fake,hopbyhop,destopt с ipfrag2, fake,fakeknown с udplen и tamper. -udplen увеличивает размер udp пакета на указанное в --dpi-desync-udplen-increment количество байтов. -Паддинг заполняется нулями по умолчанию, но можно задать свой паттерн. -Предназначено для обмана DPI, ориентирующегося на размеры пакетов. -Может сработать, если пользовательсткий протокол не привязан жестко к размеру udp пейлоада. -Режим tamper означает модификацию пакетов известных протоколов особенным для протокола образом. -На текущий момент работает только с DHT. -Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр ---hostlist будет работать. -Определяются пакеты wireguard handshake initiation и DHT (начинается с 'd1', кончается 'e'). -Для десинхронизации других протоколов обязательно указывать --dpi-desync-any-protocol. -Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp -можно изменить 4-м параметром в --ctrack-timeouts. -Атака fake полезна только для stateful DPI, она бесполезна для анализа на уровне отдельных пакетов. -По умолчанию fake наполнение - 64 нуля. Можно указать файл в --dpi-desync-fake-unknown-udp. - -IP ФРАГМЕНТАЦИЯ -В современной сети с этом все очень плохо. Фрагментированные пакеты застревают по пути, часто отбрасываются. -Иногда доходят. Иногда то доходят, то не доходят. Может зависеть от версии ipv4/ipv6. -Роутеры на базе linux могут самопроизвольно собирать или перефрагментировать пакеты. -Позиция фрагментации задается отдельно для tcp и udp. По умолчанию 24 и 8 соответственно, должна быть кратна 8. -Смещение считается с транспортного заголовка. - -Существует ряд моментов вокруг работы с фрагментами на Linux, без понимания которых может ничего не получиться. - -ipv4 : Linux дает отсылать ipv4 фрагменты, но стандартные настройки iptables в цепочке OUTPUT могут вызывать ошибки отправки. - -ipv6 : Нет способа для приложения гарантированно отослать фрагменты без дефрагментации в conntrack. -На разных системах получается по-разному. Где-то нормально уходят, где-то пакеты дефрагментируются. -Для ядер <4.16 похоже, что нет иного способа решить эту проблему, кроме как выгрузить модуль nf_conntrack, -который подтягивает зависимость nf_defrag_ipv6. Он то как раз и выполняет дефрагментацию. -Для ядер 4.16+ ситуация чуть лучше. Из дефрагментации исключаются пакеты в состоянии NOTRACK. -Чтобы не загромождать описание, смотрите пример решения этой проблемы в blockcheck.sh. - -Иногда требуется подгружать модуль ip6table_raw с параметром raw_before_defrag=1. -В openwrt параметры модулей указываются через пробел после их названий в файлах /etc/modules.d. -В традиционных системах посмотрите используется ли iptables-legacy или iptables-nft. Если legacy, то нужно создать файл -/etc/modprobe.d/ip6table_raw.conf с содержимым : -options ip6table_raw raw_before_defrag=1 -В некоторых традиционных дистрибутивах можно изменить текущий ip6tables через : update-alternatives --config ip6tables -Если вы хотите оставаться на iptables-nft, вам придется пересобрать патченную версию. Патч совсем небольшой. -В nft.c найдите фрагмент : - { - .name = "PREROUTING", - .type = "filter", - .prio = -300, /* NF_IP_PRI_RAW */ - .hook = NF_INET_PRE_ROUTING, - }, - { - .name = "OUTPUT", - .type = "filter", - .prio = -300, /* NF_IP_PRI_RAW */ - .hook = NF_INET_LOCAL_OUT, - }, -и замените везде -300 на -450. - -Это нужно сделать вручную, никакой автоматики в blockcheck.sh нет. - -Либо можно раз и навсегда избавиться от этой проблемы, используя nftables. Там можно создать netfilter hook -с любым приоритетом. Используйте приоритет -401 и ниже. - -При использовании iptables и NAT, похоже, что нет способа прицепить обработчик очереди после NAT. -MASQUERADE является финальным таргетом, после него NFQUEUE не срабатывает. -Пакет попадает в nfqws с source адресом внутренней сети, затем фрагментируется и уже не обрабатывается NAT. -Так и уходит во внешюю сеть с src ip 192.168.x.x. Следовательно, метод не срабатывает. -Видимо единственный рабочий метод - отказаться от iptables и использовать nftables. -Хук должен быть с приоритетом 101 или выше. - -tpws ------ - -tpws - это transparent proxy. - --debug=0|1|2 ; Количество буковок в output : 0(default)=тихо, 1=подробно, 2=отладка - --daemon ; демонизировать прогу - --pidfile= ; сохранить PID в файл - --user= ; менять uid процесса - --uid=uid[:gid] ; менять uid процесса - --bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес - ; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan - --bind-linklocal=no|unwanted|prefer|force - ; no : биндаться только на global ipv6 - ; unwanted (default) : предпочтительно global, если нет - LL - ; prefer : предпочительно LL, если нет - global - ; force : биндаться только на LL - --bind-iface4= ; слушать на первом ipv4 интерфейса iface - --bind-iface6= ; слушать на первом ipv6 интерфейса iface - --bind-wait-ifup= ; ждать до N секунд появления и поднятия интерфейса - --bind-wait-ip= ; ждать до N секунд получения IP адреса (если задан --bind-wait-ifup - время идет после поднятия интерфейса) - --bind-wait-ip-linklocal= - ; имеет смысл только при задании --bind-wait-ip - ; --bind-linklocal=unwanted : согласиться на LL после N секунд - ; --bind-linklocal=prefer : согласиться на global address после N секунд - --bind-wait-only ; подождать все бинды и выйти. результат 0 в случае успеха, иначе не 0. - --socks ; вместо прозрачного прокси реализовать socks4/5 proxy - --no-resolve ; запретить ресолвинг имен через socks5 - --port= ; на каком порту слушать - --maxconn= ; максимальное количество соединений от клиентов к прокси - --maxfiles= ; макс количество файловых дескрипторов (setrlimit). мин требование (X*connections+16), где X=6 в tcp proxy mode, X=4 в режиме тамперинга. - ; стоит сделать запас с коэффициентом как минимум 1.5. по умолчанию maxfiles (X*connections)*1.5+16 - --max-orphan-time=; если вы запускаете через tpws торрент-клиент с множеством раздач, он пытается установить очень много исходящих соединений, - ; большая часть из которых отваливается по таймату (юзера сидят за NAT, firewall, ...) - ; установление соединения в linux может длиться очень долго. локальный конец отвалился, перед этим послав блок данных, - ; tpws ждет подключения удаленного конца, чтобы отослать ему этот блок, и зависает надолго. - ; настройка позволяет сбрасывать такие подключения через N секунд, теряя блок данных. по умолчанию 5 сек. 0 означает отключить функцию - ; эта функция не действует на успешно подключенные ранее соединения - - --local-rcvbuf= ; SO_RCVBUF для соединений client-proxy - --local-sndbuf= ; SO_SNDBUF для соединений client-proxy - --remote-rcvbuf= ; SO_RCVBUF для соединений proxy-target - --remote-sndbuf= ; SO_SNDBUF для соединений proxy-target - --skip-nodelay ; не устанавливать в исходящих соединения TCP_NODELAY. несовместимо со split. - - --split-http-req=method|host ; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host - --split-pos= ; делить все посылы на сегменты в указанной позиции. единственная опция, работающая на не-http. при указании split-http-req он имеет преимущество на http. - --split-any-protocol ; применять split-pos к любым пакетам. по умолчанию - только к http и TLS ClientHello - --disorder ; путем манипуляций с сокетом вынуждает отправлять первым второй сегмент разделенного запроса - --hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:". - --hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase - --hostdot ; добавление точки после имени хоста : "Host: kinozal.tv." - --hosttab ; добавление табуляции после имени хоста : "Host: kinozal.tv\t" - --hostnospace ; убрать пробел после "Host:" - --hostpad= ; добавить паддинг-хедеров общей длиной перед Host: - --domcase ; домен после Host: сделать таким : TeSt.cOm - --methodspace ; добавить пробел после метода : "GET /" => "GET /" - --methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /" - --unixeol ; конвертировать 0D0A в 0A и использовать везде 0A - --hostlist= ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются. - ; в файле должен быть хост на каждой строке. - ; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска. - ; по сигналу HUP список будет перечитан при следующем принятом соединении - ; список может быть запакован в gzip. формат автоматически распознается и разжимается - ; списков может быть множество, они обьединяются. пустой общий лист = его отсутствие - ; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello. - --hostlist-exclude= ; не применять дурение к доменам из листа. может быть множество листов, они обьединяются - - -Параметры манипуляции могут сочетаться в любых комбинациях. - -В случае http запроса split-http-req имеет преимущество над split-pos. -split-pos по умолчанию работает только на http и TLS ClientHello. -Чтобы он работал на любых пакетах, укажите --split-any-protocol. - -На прикладном уровне в общем случае нет гарантированного средства заставить ядро выплюнуть -блок данных, порезанным в определенном месте. ОС держит буфер отсылки (SNDBUF) у каждого сокета. -Если у сокета включена опция TCP_NODELAY и буфер пуст, то каждый send приводит к отсылке -отдельного ip пакета или группы пакетов, если блок не вмещается в один ip пакет. -Однако, если в момент send уже имеется неотосланный буфер, то ОС присоединит данные к нему, -никакой отсылки отдельным пакетом не будет. Но в этом случае и так нет никакой гарантии, -что какой-то блок сообщения пойдет в начале пакета, на что собственно и заточены DPI. -Разбиение будет производится согласно MSS, который зависит от MTU исходящего интерфейса. -Таким образом DPI, смотрящие в начало поля данных TCP пакета, будут поломаны в любом случае. -Протокол http относится к запрос-ответным протоколам. Новое сообщение посылается только тогда, -когда сервер получил запрос и полностью вернул ответ. Значит запрос фактически был не только отослан, -но и принят другой стороной, а следовательно буфер отсылки пуст, и следующие 2 send приведут -к отсылке сегментов данных разными ip пакетами. -Резюме : tpws гарантирует сплит только за счет раздельных вызовов send, что на практике -вполне достаточно для протоколов http(s). - -tpws может биндаться на множество интерфейсов и IP адресов (до 32 шт). -Порт всегда только один. -Параметры --bind-iface* и --bind-addr создают новый бинд. -Остальные параметры --bind-* относятся к последнему бинду. -Для бинда на все ipv4 укажите --bind-addr "0.0.0.0", на все ipv6 - "::". --bind-addr="" - биндаемся на все ipv4 и ipv6. -Выбор режима использования link local ipv6 адресов (fe80::/8) : ---bind-iface6 --bind-linklocal=no : сначала приватный адрес fc00::/7, затем глобальный адрес ---bind-iface6 --bind-linklocal=unwanted : сначала приватный адрес fc00::/7, затем глобальный адрес, затем link local. ---bind-iface6 --bind-linklocal=prefer : сначала link local, затем приватный адрес fc00::/7, затем глобальный адрес. ---bind-iface6 --bind-linklocal=force : только link local -Если не указано ни одного бинда, то создается бинд по умолчанию на все адреса всех интерфейсов. -Для бинда на конкретный link-local address делаем так : --bind-iface6=fe80::aaaa:bbbb:cccc:dddd%iface-name -Параметры --bind-wait* могут помочь в ситуациях, когда нужно взять IP с интерфейса, но его еще нет, он не поднят -или не сконфигурирован. -В разных системах события ifup ловятся по-разному и не гарантируют, что интерфейс уже получил IP адрес определенного типа. -В общем случае не существует единого механизма повеситься на событие типа "на интерфейсе X появился link local address". -Для бинда на известный ip, когда еще интерфейс не сконфигурирован, нужно делать так : --bind-addr=192.168.5.3 --bind-wait-ip=20 -В режиме transparent бинд возможен на любой несуществующий адрес, в режиме socks - только на существующий. - -Параметры rcvbuf и sndbuf позволяют установить setsockopt SO_RCVBUF SO_SNDBUF для локального и удаленного соединения. - -Если не указан ни один из параметров модификации содержимого, tpws работает в режиме "tcp proxy mode". -Он отличается тем, что в оба конца применяется splice для переброски данных из одного сокета в другой -без копирования в память процесса. Практически - это то же самое, но может быть чуть побыстрее. -TCP проксирование может быть полезно для обхода блокировок, когда DPI спотыкается на экзотических -хедерах IP или TCP. Вы вряд ли сможете поправить хедеры, исходящие от айфончиков и гаджетиков, -но на linux сможете влиять на них в какой-то степени через sysctl. -Когда соединение проходит через tpws, фактически прокси-сервер сам устанавливает подключение к удаленному -узлу от своего имени, и на это распространяются настройки системы, на которой работает прокси. -tpws можно использовать на мобильном устройстве, раздающем интернет на тарифе сотового оператора, -где раздача запрещена, в socks режиме даже без рута. Соединения от tpws неотличимы от соединений -с самого раздающего устройства. Отличить можно только по содержанию (типа обновлений windows). -Заодно можно и обойти блокировки. 2 зайца одним выстрелом. -Более подробную информацию по вопросу обхода ограничений операторов гуглите на 4pda.ru. - -Режим "--socks" не требует повышенных привилегий (кроме бинда на привилегированные порты 1..1023). -Поддерживаются версии socks 4 и 5 без авторизации. Версия протокола распознается автоматически. -Подключения к IP того же устройства, на котором работает tpws, включая localhost, запрещены. -socks5 позволяет удаленно ресолвить хосты (curl : --socks5-hostname firefox : socks_remote_dns=true). -tpws поддерживает эту возможность, однако используется блокирующий ресолвинг. Пока система -ресолвит хост (это может занять секунды), вся активность останавливается. -tpws полностью работает на асинхронных сокетах, но ресолвинг может попортить эту модель. -С ним возможны атаки DoS на tpws. Если tpws обслуживает множество клиентов, то из-за частого -ресолвинга качество обслуживания может существенно ухудшиться. -Если удаленный ресолвинг создает проблемы, настройте клиенты на локальный ресолвинг, включите опцию ---no-resolve на стороне tpws. - -Параметр --hostpad= добавляет паддинг-хедеров перед Host: на указанное количество байтов. -Если размер слишком большой, то идет разбивка на разные хедеры по 2K. -Общий буфер приема http запроса - 64K, больший паддинг не поддерживается, да и http сервера -такое уже не принимают. -Полезно против DPI, выполняющих реассемблинг TCP с ограниченным буфером. -Если техника работает, то после некоторого количества bytes http запрос начнет проходить до сайта. -Если при этом критический размер padding около MTU, значит скорее всего DPI не выполняет реассемблинг пакетов, и лучше будет использовать обычные опции --split-… -Если все же реассемблинг выполняется, то критический размер будет около размера буфера DPI. Он может быть 4K или 8K, возможны и другие значения. - ---disorder - это попытка симулировать режим disorder2 nfqws , используя особенности ОС по реализации stream сокетов. -Однако, в отличие от nfqws, здесь не требуются повышенные привилегии. -Реализовано это следующим образом. У сокета есть возможность выставить TTL. Все пакеты будут отправляться с ним. -Перед отправкой первого сегмента ставим TTL=1. Пакет будет дропнут на первом же роутере, он не дойдет ни до DPI, ни до сервера. -Затем возвращаем TTL в значение по умолчанию. ОС отсылает второй сегмент, и он уже доходит до сервера. -Сервер возвращает SACK, потому что не получил первый кусок, и ОС его отправляет повторно, но здесь уже мы ничего не делаем. -Этот режим работает как ожидается на Linux и MacOS. Однако, на FreeBSD и OpenBSD он работает не так хорошо. -Ядро этих ОС отсылает ретрансмиссию в виде полного пакета. Потому выходит, что до сервера идет сначала второй кусок, -а потом полный запрос без сплита. На него может отреагировать DPI штатным образом. ---disorder является дополнительным флагом к любому сплиту. Сам по себе он не делает ничего. - ---skip-nodelay может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws. -Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения -подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз. - - -Способы получения списка заблокированных IP -------------------------------------------- - -!!! nftables не могут работать с ipset-ами. Собственный аналогичный механизм требует огромного количество RAM -!!! для загрузки больших листов. Например, для загона 100K записей в nfset не хватает даже 256 Mb. -!!! Если вам нужны большие листы на домашних роутерах, откатывайтесь на iptables+ipset. - -1) Внесите заблокированные домены в ipset/zapret-hosts-user.txt и запустите ipset/get_user.sh -На выходе получите ipset/zapret-ip-user.txt с IP адресами. - -Cкрипты с названием get_reestr_* оперируют дампом реестра заблокированных сайтов : - -2) ipset/get_reestr_resolve.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса -в файл ipset/zapret-ip.txt.gz. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде, -что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко -банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости -от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени. -Используется мультипоточный ресолвер mdig (собственная разработка). - -3) ipset/get_reestr_preresolved.sh. то же самое, что и 2), только берется уже заресолвленый список -со стороннего ресурса. - -4) ipset/get_reestr_preresolved_smart.sh. то же самое, что и 5), с добавлением всего диапазона некоторых -автономных систем (прыгающие IP адреса из cloudflare, facebook, ...) и некоторых поддоменов блокируемых сайтов - -Cкрипты с названием get_antifilter_* оперируют списками адресов и масок подсетей с сайтов antifilter.network и antifilter.download : - -5) ipset/get_antifilter_ip.sh. получает лист https://antifilter.download/list/ip.lst. - -6) ipset/get_antifilter_ipsmart.sh. получает лист https://antifilter.network/download/ipsmart.lst. -умная суммаризация отдельных адресов из ip.lst по маскам от /32 до /22 - -7) ipset/get_antifilter_ipsum.sh. получает лист https://antifilter.download/list/ipsum.lst. -суммаризация отдельных адресов из ip.lst по маске /24 - -8) ipset/get_antifilter_ipresolve.sh. получает лист https://antifilter.download/list/ipresolve.lst. -пре-ресолвленный список, аналогичный получаемый при помощи get_reestr_resolve. только ipv4. - -9) ipset/get_antifilter_allyouneed.sh. получает лист https://antifilter.download/list/allyouneed.lst. -Суммарный список префиксов, созданный из ipsum.lst и subnet.lst. - -Все варианты рассмотренных скриптов автоматически создают и заполняют ipset. -Варианты 2-9 дополнительно вызывают вариант 1. - -10) ipset/get_config.sh. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config -Если переменная не определена, то ресолвятся лишь листы для ipset nozapret/nozapret6. - -Листы РКН все время изменяются. Возникают новые тенденции. Требования к RAM могут меняться. -Поэтому необходима нечастая, но все же регулярная ревизия что же вообще у вас происходит на роутере. -Или вы можете узнать о проблеме лишь когда у вас начнет постоянно пропадать wifi, и вам придется -его перезагружать каждые 2 часа (метод кувалды). - -Самые щадящие варианты по RAM - get_antifilter_allyouneed.sh, get_antifilter_ipsum.sh. - -Листы zapret-ip.txt и zapret-ipban.txt сохраняются в сжатом виде в файлы .gz. -Это позволяет снизить их размер во много раз и сэкономить место на роутере. -Отключить сжатие листов можно параметром конфига GZIP_LISTS=0. - -На роутерах не рекомендуется вызывать эти скрипты чаще раза за 2 суток, поскольку сохранение идет -либо во внутреннюю флэш память роутера, либо в случае extroot - на флэшку. -В обоих случаях слишком частая запись может убить флэшку, но если это произойдет с внутренней -флэш памятью, то вы просто убьете роутер. - -Принудительное обновление ipset выполняет скрипт ipset/create_ipset.sh. -Если передан параметр "no-update", скрипт не обновляет ipset, а только создает его при его отсутствии и заполняет. -Это полезно, когда могут случиться несколько последовательных вызовов скрипта. Нет смысла несколько раз перезаполнять -ipset, это длительная операция на больших листах. Листы можно обновлять раз в несколько суток, и только тогда -вызывать create_ipset без параметра "no-update". Во всех остальных случаях стоит применять "no-update". - -Список РКН уже достиг внушительных размеров в сотни тысяч IP адресов. Поэтому для оптимизации ipset -применяется утилита ip2net. Она берет список отдельных IP адресов и пытается интеллектуально создать из него подсети для сокращения -количества адресов. ip2net отсекает неправильные записи в листах, гарантируя осутствие ошибок при их загрузке. -ip2net написан на языке C, поскольку операция ресурсоемкая. Иные способы роутер может не потянуть. - -Можно внести список доменов в ipset/zapret-hosts-user-ipban.txt. Их ip адреса будут помещены -в отдельный ipset "ipban". Он может использоваться для принудительного завертывания всех -соединений на прозрачный proxy "redsocks" или на VPN. - -IPV6 : если включен ipv6, то дополнительно создаются листы с таким же именем, но с "6" на конце перед расширением. -zapret-ip.txt => zapret-ip6.txt -Создаются ipset-ы zapret6 и ipban6. -Листы с antifilter не содержат список ipv6 адресов. - -СИСТЕМА ИСКЛЮЧЕНИЯ IP. Все скрипты ресолвят файл zapret-hosts-user-exclude.txt, создавая zapret-ip-exclude.txt и zapret-ip-exclude6.txt. -Они загоняются в ipset-ы nozapret и nozapret6. Все правила, создаваемые init скриптами, создаются с учетом этих ipset. -Помещенные в них IP не участвуют в процессе. -zapret-hosts-user-exclude.txt может содержать домены, ipv4 и ipv6 адреса или подсети. - -FreeBSD. Скрипты ipset/*.sh работают так же на FreeBSD. Вместо ipset они создают lookup таблицы ipfw с аналогичными именами. -ipfw таблицы в отличие от ipset могут содержать как ipv4, так и ipv6 адреса и подсети в одной таблице, поэтому разделения нет. - -Параметр конфига LISTS_RELOAD задает произвольную команду для перезагрузки листов. -Это особенно полезно на BSD системах с PF. -LISTS_RELOAD=- отключает перезагрузку листов. - - -ip2net ------- - -Утилита ip2net предназначена для преобразования ipv4 или ipv6 списка ip в список подсетей -с целью сокращения размера списка. Входные данные берутся из stdin, выходные выдаются в stdout. - - -4 ; лист - ipv4 (по умолчанию) - -6 ; лист - ipv6 - --prefix-length=min[-max] ; диапазон рассматриваемых длин префиксов. например : 22-30 (ipv4), 56-64 (ipv6) - --v4-threshold=mul/div ; ipv4 : включать подсети, в которых заполнено по крайней мере mul/div адресов. например : 3/4 - --v6-threshold=N ; ipv6 : минимальное количество ip для создания подсети - -В списке могут присутствовать записи вида ip/prefix и ip1-ip2. Такие записи выкидываются в stdout без изменений. -Они принимаются командой ipset. ipset умеет для листов hash:net из ip1-ip2 делать оптимальное покрытие ip/prefix. -ipfw из FreeBSD понимает ip/prefix, но не понимает ip1-ip2. -ip2net фильтрует входные данные, выкидывая неправильные IP адреса. - -Выбирается подсеть, в которой присутствует указанный минимум адресов. -Для ipv4 минимум задается как процент от размера подсети (mul/div. например, 3/4), для ipv6 минимум задается напрямую. - -Размер подсети выбирается следующим алгоритмом : -Сначала в указанном диапазоне длин префиксов ищутся подсети, в которых количество адресов - максимально. -Если таких сетей найдено несколько, берется наименьшая сеть (префикс больше). -Например, заданы параметры v6_threshold=2 prefix_length=32-64, имеются следующие ipv6 : -1234:5678:aaaa::5 -1234:5678:aaaa::6 -1234:5678:aaac::5 -Результат будет : -1234:5678:aaa8::/45 -Эти адреса так же входят в подсеть /32. Однако, нет смысла проходиться ковровой бомбардировкой, -когда те же самые адреса вполне влезают в /45 и их ровно столько же. -Если изменить v6_threshold=4, то результат будет : -1234:5678:aaaa::5 -1234:5678:aaaa::6 -1234:5678:aaac::5 -То есть ip не объединятся в подсеть, потому что их слишком мало. -Если изменить prefix_length=56-64, результат будет : -1234:5678:aaaa::/64 -1234:5678:aaac::5 - -Требуемое процессорное время для вычислений сильно зависит от ширины диапазона длин префиксов, размера искомых подсетей и длины листа. -Если ip2net думает слишком долго, не используйте слишком большие подсети и уменьшите диапазон длин префиксов. -Учтите, что арифметика mul/div - целочисленная. При превышении разрядной сетки 32 bit результат непредсказуем. -Не надо делать такое : 5000000/10000000. 1/2 - гораздо лучше. - - -Фильтрация по именам доменов ----------------------------- - -Альтернативой ipset является использование tpws или nfqws со списком доменов. -Оба демона принимают неограниченное количество листов include (--hostlist) и exclude (--hostlist-exclude). -Все листы одного типа обьединяются, и таким образом остаются только 2 листа. -Прежде всего проверяется exclude list. При вхождении в него происходит отказ от дурения. -Далее при наличии include list проверяется домен на вхождение в него. При невхождении в список отказ от дурения. -Пустой список приравнивается к его отсутствию. -В иных случаях происходит дурение. -Нет ни одного списка - дурение всегда. -Есть только exclude список - дурение всех, кроме. -Есть только include список - дурение только их. -Есть оба - дурение только include, кроме exclude. - -В системе запуска это обыграно следующим образом. -Присутствуют 2 include списка : -ipset/zapret-hosts-users.txt.gz или ipset/zapret-hosts-users.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 - -При режиме фильтрации MODE_FILTER=hostlist система запуска передает nfqws или tpws все листы, файлы которых присутствуют. -Если вдруг листы include присутствуют, но все они пустые, то работа аналогична отсутствию include листа. -Файл есть, но не смотря на это дурится все, кроме exclude. -Если вам нужен именно такой режим - не обязательно удалять zapret-hosts-users.txt. Достаточно сделать его пустым. - -Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает. - -Список доменов РКН может быть получен скриптами ipset/get_reestr_hostlist.sh или ipset/get_antizapret_domains.sh -- кладется в ipset/zapret-hosts.txt.gz. - -Чтобы обновить списки, перезапускать nfqws или tpws не нужно. Обновляете файлы, затем даете сигнал HUP. -По HUP листы будут перечитаны. Если вдруг какого-то листа не окажется, процесс завершится с ошибкой. -Скрипты получения листов из ipset сами выдают HUP в конце. - -При фильтрации по именам доменов демон должен запускаться без фильтрации по ipset. -tpws и nfqws решают нужно ли применять дурение в зависимости от хоста, полученного из протокола прикладного уровня (http, tls, quic). -При использовании больших списков, в том числе списка РКН, оцените объем RAM на роутере ! -Если после запуска демона RAM под завязку или случаются oom, значит нужно отказаться от таких больших списков. - - -Проверка провайдера -------------------- - -Перед настройкой нужно провести исследование какую бяку устроил вам ваш провайдер. - -Нужно выяснить не подменяет ли он DNS и какой метод обхода DPI работает. -В этом вам поможет скрипт blockcheck.sh. - -Если DNS подменяется, но провайдер не перехватывает обращения к сторонним DNS, поменяйте DNS на публичный. -Например : 8.8.8.8, 8.8.4.4, 1.1.1.1, 1.0.0.1, 9.9.9.9 -Если DNS подменяется и провайдер перехватывает обращения к сторонним DNS, настройте dnscrypt. -Еще один эффективный вариант - использовать ресолвер от yandex 77.88.8.88 на нестандартном порту 1253. -Многие провайдеры не анализируют обращения к DNS на нестандартных портах. - -Следует прогнать blockcheck по нескольким заблокированным сайтам и выявить общий характер блокировок. -Разные сайты могут быть заблокированы по-разному, нужно искать такую технику, которая работает на большинстве. -Чтобы записать вывод blockcheck.sh в файл, выполните : ./blockcheck.sh | tee /tmp/blockcheck.txt - -Проанализируйте какие методы дурения DPI работают, в соответствии с ними настройте /opt/zapret/config. - -Имейте в виду, что у провайдеров может быть несколько DPI или запросы могут идти через разные каналы -по методу балансировки нагрузки. Балансировка может означать, что на разных ветках разные DPI или -они находятся на разных хопах. Такая ситуация может выражаться в нестабильности работы обхода. -Дернули несколько раз curl. То работает, то connection reset или редирект. blockcheck.sh выдает -странноватые результаты. То split работает на 2-м. хопе, то на 4-м. Достоверность результата вызывает сомнения. -В этом случае задайте несколько повторов одного и того же теста. Тест будет считаться успешным только, -если все попытки пройдут успешно. - - -Выбор параметров ----------------- - -Файл /opt/zapret/config используется различными компонентами системы и содержит основные настройки. -Его нужно просмотреть и при необходимости отредактировать. - -На linux системах можно выбрать использовать iptables или nftables. -По умолчанию на традиционных linux выбирается nftables, если установлен nft. -На openwrt по умолчанию выбирается nftables на новых версиях с firewall4. - -FWTYPE=iptables - -Основной режим : -tpws - tpws в режиме transparent -tpws-socks - tpws в режиме socks - вешается на localhost и LAN интерфейс (если задан IFACE_LAN или если система - OpenWRT). порт 988 -nfqws - nfqws -filter - только заполнить ipset или загрузить hostlist -custom - нужно самому запрограммировать запуск демонов в init скрипте и правила iptables - -MODE=tpws - -Применять ли дурение к HTTP : - -MODE_HTTP=1 - -Применять ли дурение к последовательным http запросам в одном tcp соединении (http keeaplive). -Относится только к nfqws. Выключение данной функции способно сэкономить загрузку процессора. -tpws всегда работает с http keepalive - -MODE_HTTP_KEEPALIVE=0 - -Применять ли дурение к HTTPS : - -MODE_HTTPS=1 - -Применять ли дурение к QUIC : - -MODE_QUIC=0 - -Режим фильтрации хостов : -none - применять дурение ко всем хостам -ipset - ограничить дурение ipset-ом zapret/zapret6 -hostlist - ограничить дурение списком хостов из файла - -MODE_FILTER=none - -Опции tpws : - -TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3" - -Опции nfqws для атаки десинхронизации DPI : - -DESYNC_MARK=0x40000000 -NFQWS_OPT_DESYNC="--dpi-desync=fake --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" - -Задание раздельных опций nfqws для http и https и для версий ip протоколов 4,6 : - -NFQWS_OPT_DESYNC_HTTP="--dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" -NFQWS_OPT_DESYNC_HTTPS="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" -NFQWS_OPT_DESYNC_HTTP6="--dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" -NFQWS_OPT_DESYNC_HTTPS6="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" - -Если какая-то из переменных NFQWS_OPT_DESYNC_HTTP/NFQWS_OPT_DESYNC_HTTPS не определена, -берется значение NFQWS_OPT_DESYNC. -Если какая-то из переменных NFQWS_OPT_DESYNC_HTTP6/NFQWS_OPT_DESYNC_HTTPS6 не определена, -берется значение NFQWS_OPT_DESYNC_HTTP/NFQWS_OPT_DESYNC_HTTPS. - -Опции дурения для QUIC : -NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake" -NFQWS_OPT_DESYNC_QUIC6="--dpi-desync=hopbyhop" -Если NFQWS_OPT_DESYNC_QUIC6 не задано, то берется NFQWS_OPT_DESYNC_QUIC. - -Настройка системы управления выборочным traffic offload (только если поддерживается) -donttouch : выборочное управление отключено, используется системная настройка, простой инсталятор выключает системную настройку, если она не совместима с выбранным режимом -none : выборочное управление отключено, простой инсталятор выключает системную настройку -software : выборочное управление включено в режиме software, простой инсталятор выключает системную настройку -hardware : выборочное управление включено в режиме hardware, простой инсталятор выключает системную настройку - -FLOWOFFLOAD=donttouch - -Параметр GETLIST указывает инсталятору install_easy.sh какой скрипт дергать -для обновления списка заблокированных ip или хостов. -Он же вызывается через get_config.sh из запланированных заданий (crontab или systemd timer). -Поместите сюда название скрипта, который будете использовать для обновления листов. -Если не нужно, то параметр следует закомментировать. - -Можно индивидуально отключить ipv4 или ipv6. Если параметр закомментирован или не равен "1", -использование протокола разрешено. -#DISABLE_IPV4=1 -DISABLE_IPV6=1 - -Количество потоков для многопоточного DNS ресолвера mdig (1..100). -Чем их больше, тем быстрее, но не обидится ли на долбежку ваш DNS сервер ? -MDIG_THREADS=30 - -Место для хранения временных файлов. При скачивании огромных реестров в /tmp места может не хватить. -Если файловая система на нормальном носителе (не встроенная память роутера), то можно -указать место на флэшке или диске. -TMPDIR=/opt/zapret/tmp - -Опции для создания ipset-ов и nfset-ов - -SET_MAXELEM=262144 -IPSET_OPT="hashsize 262144 maxelem 2097152" - -Хук, позволяющий внести ip адреса динамически. $1 = имя таблицы -Адреса выводятся в stdout. В случае nfset автоматически решается проблема возможного пересечения интервалов. -IPSET_HOOK="/etc/zapret.ipset.hook" - -ПРО РУГАНЬ в dmesg по поводу нехватки памяти. -Может так случиться, что памяти в системе достаточно, но при попытке заполнить огромный ipset -ядро начинает громко ругаться, ipset заполняется не полностью. -Вероятная причина в том, что превышается hashsize, заданный при создании ipset (create_ipset.sh). -Происходит переаллокация списка, не находится непрерывных фрагментов памяти нужной длины. -Это лечится увеличением hashsize. Но чем больше hashsize, тем больше занимает ipset в памяти. -Задавать слишком большой hashsize для недостаточно больших списков нецелесообразно. - -Опции для вызова ip2net. Отдельно для листов ipv4 и ipv6. -IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4" -IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5" - -Включить или выключить сжатие больших листов в скриптах ipset/*.sh. По умолчанию включено. -GZIP_LISTS=1 - -Команда для перезагрузки ip таблиц фаервола. -Если не указано или пустое, выбирается автоматически ipset или ipfw при их наличии. -На BSD системах с PF нет автоматической загрузки. Там нужно указать команду явно : pfctl -f /etc/pf.conf -На более новых pfctl (есть в новых FreeBSD, нет в OpenBSD 6.8) можно дать команду загрузки только таблиц : pfctl -Tl -f /etc/pf.conf -"-" означает отключение загрузки листов даже при наличии поддерживаемого backend. -#LISTS_RELOAD="pfctl -f /etc/pf.conf" -#LISTS_RELOAD=- - -В openwrt существует сеть по умолчанию 'lan'. Только трафик с этой сети будет перенаправлен на tpws. -Но возможно задать другие сети или список сетей : -OPENWRT_LAN="lan lan2 lan3" - -Параметр INIT_APPLY_FW=1 разрешает init скрипту самостоятельно применять правила iptables. -При иных значениях или если параметр закомментирован, правила применены не будут. -Это полезно, если у вас есть система управления фаерволом, в настройки которой и следует прикрутить правила. -На openwrt неприменимо при использовании firewall3+iptables. - -Следующие настройки не актуальны для openwrt : - -Если ваша система работает как роутер, то нужно вписать названия внутренних и внешних интерфейсов : -IFACE_LAN=eth0 -IFACE_WAN=eth1 -IFACE_WAN6="henet ipsec0" -Несколько интерфейсов могут быть вписаны через пробел. -Если IFACE_WAN6 не задан, то берется значение IFACE_WAN. - -ВАЖНО : настройка маршрутизации , маскарада и т.д. не входит в задачу zapret. -Включаются только режимы, обеспечивающие перехват транзитного трафика. -Возможно определить несколько интерфейсов следующим образом : IFACE_LAN="eth0 eth1 eth2" - -Прикручивание к системе управления фаерволом или своей системе запуска ----------------------------------------------------------------------- - -Если вы используете какую-то систему управления фаерволом, то она может вступать в конфликт -с имеющимся скриптом запуска. При повторном применении правил она могла бы поломать настройки iptables от zapret. -В этом случае правила для iptables должны быть прикручены к вашему фаерволу отдельно от запуска tpws или nfqws. - -Следующие вызовы позволяют применить или убрать правила iptables отдельно : - - /opt/zapret/init.d/sysv/zapret start_fw - /opt/zapret/init.d/sysv/zapret stop_fw - /opt/zapret/init.d/sysv/zapret restart_fw - -А так можно запустить или остановить демоны отдельно от фаервола : - - /opt/zapret/init.d/sysv/zapret start_daemons - /opt/zapret/init.d/sysv/zapret stop_daemons - /opt/zapret/init.d/sysv/zapret restart_daemons - -nftables сводят практически на нет конфликты между разными системами управления, поскольку позволяют -использовать независимые таблицы и хуки. Используется отдельная nf-таблица "zapret". -Если ваша система ее не будет трогать, скорее всего все будет нормально. - -Для nftables предусмотрено несколько дополнительных вызовов : - -Посмотреть set-ы интерфейсов, относящихся к lan, wan и wan6. По ним идет завертывание трафика. -А так же таблицу flow table с именами интерфейсов ingress hook. - /opt/zapret/init.d/sysv/zapret list_ifsets - -Обновить set-ы интерфейсов, относящихся к lan, wan и wan6. -Для традиционных linux список интерфейсов берется из переменных конфига IFACE_LAN, IFACE_WAN. -Для openwrt определяется автоматически. Множество lanif может быть расширено параметром OPENWRT_LAN. -Все интерфейсы lan и wan так же добавляются в ingress hook от flow table. - /opt/zapret/init.d/sysv/zapret reload_ifsets - -Просмотр таблицы без содержимого set-ов. Вызывает nft -t list table inet zapret - /opt/zapret/init.d/sysv/zapret list_table - -Так же возможно прицепиться своим скриптом к любой стадии применения и снятия фаервола со стороны zapret скриптов : - -INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up" -INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up" -INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down" -INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down" - -Эти настройки доступны в config. -Может быть полезно, если вам нужно использовать nftables set-ы, например ipban/ipban6. -nfset-ы принадлежат только одной таблице, следовательно вам придется писать правила для таблицы zapret, -а значит нужно синхронизироваться с применением/снятием правил со стороны zapret скриптов. - - -Вариант custom --------------- - -custom код вынесен в отдельный shell include -/opt/zapret/init.d/sysv/custom -или -/opt/zapret/init.d/openwrt/custom - -Нужно свой код вписать в функции : -zapret_custom_daemons -zapret_custom_firewall -zapret_custom_firewall_nft - -В файле custom пишите ваш код, пользуясь хелперами из "functions" или "zapret". -Смотрите как там сделано добавление iptables или запуск демонов. -Используя хелпер функции, вы избавитесь от необходимости учитывать все возможные случаи -типа наличия/отсутствия ipv6, является ли система роутером, имена интерфейсов, ... -Хелперы это учитывают , вам нужно сосредоточиться лишь на фильтрах {ip,nf}tables и -параметрах демонов. - -Код для openwrt и sysv немного отличается. В sysv нужно обрабатывать и запуск, и остановку демонов. -Запуск это или остановка передается в параметре $1 (0 или 1). -В openwrt за остановку отвечает procd. - -Для фаервола кастом пишется отдельно для iptables и nftables. Все очень похоже, но отличается -написание фильтров и названия процедур хелперов. Если вам не нужны iptables или nftables - -можете не писать соответствующую функцию. - -Готовый custom скрипт custom-tpws4http-nfqws4https позволяет применить дурение -tpws к http и nfqws к https. При этом поддерживаются установки из config. -Его можно использовать как стартовую точку для написания своих скриптов. - - -Простая установка ------------------ - -install_easy.sh автоматизирует ручные варианты процедур установки (см manual_setup.txt). -Он поддерживает OpenWRT, linux системы на базе systemd или openrc и MacOS. - -Для более гибкой настройки перед запуском инсталятора следует выполнить раздел "Выбор параметров". - -Если система запуска поддерживается, но используется не поддерживаемый инсталятором менеджер пакетов -или названия пакетов не соответствуют прописанным в инсталятор, пакеты нужно установить вручную. -Всегда требуется curl. ipset - только для режима iptables, для nftables - не нужен. - -Для совсем обрезанных дистрибутивов (alpine) требуется отдельно установить iptables и ip6tables, либо nftables. - -В комплекте идут статические бинарики для большинства архитектур. Какой-то из них подойдет -с вероятностью 99%. Но если у вас экзотическая система, инсталятор попробует собрать бинарики сам -через make. Для этого нужны gcc, make и необходимые -dev пакеты. Можно форсировать режим -компиляции следующим вызовом : - - install_easy.sh make - -Под openwrt все уже сразу готово для использования системы в качестве роутера. -Имена интерфейсов WAN и LAN известны из настроек системы. -Под другими системами роутер вы настраиваете самостоятельно. Инсталятор в это не вмешивается. -Инсталятор в зависимости от выбранного режима может спросить LAN и WAN интерфейсы. -Нужно понимать, что заворот проходящего трафика на tpws в прозрачном режиме происходит до выполнения маршрутизации, -следовательно возможна фильтрация по LAN и невозможна по WAN. -Решение о завороте на tpws локального исходящего трафика принимается после выполнения маршрутизации, -следовательно ситуация обратная : LAN не имеет смысла, фильтрация по WAN возможна. -Заворот на nfqws происходит всегда после маршрутизации, поэтому к нему применима только фильтрация по WAN. -Возможность прохождения трафика в том или ином направлении настраивается вами в процессе конфигурации роутера. - -Деинсталяция выполняется через uninstall_easy.sh - - -Простая установка на openwrt ----------------------------- - -Работает только если у вас на роутере достаточно места. - -Копируем zapret на роутер в /tmp. - -Запускаем установщик : - /tmp/zapret/install_easy.sh -Он скопирует в /opt/zapret только необходимый минимум файлов : - config - install_easy.sh - uninstall_easy.sh - install_bin.sh - init.d/openwrt/* - ipset/* - binaries/<ваша архитектура>/{tpws,nfqws,ip2net,mdig} - -После успешной установки можно удалить zapret из tmp для освобождения RAM : - rm -r /tmp/zapret - -Для более гибкой настройки перед запуском инсталятора следует выполнить раздел "Выбор параметров". - - -Android -------- - -Без рута забудьте про nfqws и tpws в режиме transparent proxy. tpws будет работать только в режиме --socks. - -Ядра Android имеют поддержку NFQUEUE. nfqws работает. - -В стоковых ядрах нет поддержки ipset. В общем случае сложность задачи по поднятию ipset варьируется от -"не просто" до "почти невозможно". Если только вы не найдете готовое собранное ядро под ваш девайс. - -tpws будет работать в любом случае, он не требует чего-либо особенного. -В android нет /etc/passwd, потому опция --user не будет работать. Вместо нее можно -пользоваться числовыми user id и опцией --uid. -Рекомендую использовать gid 3003 (AID_INET). Иначе можете получить permission denied на создание сокета. -Например : --uid 1:3003 -В iptables укажите : "! --uid-owner 1" вместо "! --uid-owner tpws". -Напишите шелл скрипт с iptables и tpws, запускайте его средствами вашего рут менеджера. -Скрипты автозапуска лежат тут : -magisk : /data/adb/service.d -supersu : /system/su.d - -nfqws может иметь такой глюк. При запуске с uid по умолчанию (0x7FFFFFFF) при условии работы на сотовом интерфейсе -и отключенном кабеле внешнего питания система может частично виснуть. Перестает работать тач и кнопки, -но анимация на экране может продолжаться. Если экран был погашен, то включить его кнопкой power невозможно. -Это, видимо, связано с переводом в suspend процессов с определенным UID. UID соответствует приложению или -системному сервису. По UID android определяет политику power saving. -Так же возможно, что глюк связан с кривым драйвером сотового интерфейса от китайцев, поскольку при использовании -wifi такого не наблюдается. suspend обработчика nfqueue на обычном linux не вызывает подобных фатальных последствий. -Изменение UID на низкий (--uid 1 подойдет) позволяет решить эту проблему. -Глюк был замечен на android 8.1 на девайсе , основанном на платформе mediatek. - -Ответ на вопрос куда поместить tpws на android без рута, чтобы потом его запускать из приложений. -Файл заливаем через adb shell в /data/local/tmp/, лучше всего в субфолдер. -mkdir /data/local/tmp/zapret -adb push tpws /data/local/tmp/zapret -chmod 755 /data/local/tmp/zapret /data/local/tmp/zapret/tpws -chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws - -Мобильные модемы и роутеры huawei ---------------------------------- - -Устройства типа E3372, E8372, E5770 разделяют общую идеологию построения системы. -Имеются 2 вычислительных ядра. Одно ядро выполняет vxworks, другое - linux. -На 4pda имеются модицифированные прошивки с telnet и adb. Их и нужно использовать. - -Дальнейшие утверждения проверены на E8372. На других может быть аналогично или похоже. -Присутствуют дополнительные аппаратные блоки для offload-а сетевых функций. -Не весь трафик идет через linux. Исходящий трафик с самого модема проходит -цепочку OUTPUT нормально, на FORWARD =>wan часть пакетов выпадает из tcpdump. - -tpws работает обычным образом. - -nfqueue поломан. можно собрать фиксящий модуль https://github.com/im-0/unfuck-nfqueue-on-e3372h, -используя исходники с huawei open source. Исходники содержат тулчейн и полусобирающееся, -неактуальное ядро. Конфиг можно взять с рабочего модема из /proc/config.gz. -С помощью этих исходников умельцы могут собрать модуль unfuck_nfqueue.ko. -После его применения NFQUEUE и nfqws для arm работают нормально. - -Чтобы избежать проблемы с offload-ом при использвании nfqws, следует комбинировать tpws в режиме tcp proxy и nfqws. -Правила NFQUEUE пишутся для цепочки OUTPUT. -connbytes придется опускать, поскольку модуля в ядре нет. Но это не смертельно. - -Скрипт автозапуска - /system/etc/autorun.sh. Создайте свой скрипт настройки zapret, -запускайте из конца autorun.sh через "&". Скрипт должен в начале делать sleep 5, чтобы дождаться -поднятия сети и iptables от huawei. - -ПРЕДУПРЕЖДЕНИЕ. -На этом модеме происходят хаотические сбросы соединений tcp по непонятным причинам. -Выглядит это так, если запускать curl с самого модема : - curl www.ru - curl: (7) Failed to connect to www.ru port 80: Host is unreachable -Возникает ошибка сокета EHOSTUNREACH (errno -113). То же самое видно в tpws. -В броузере не подгружаются части веб страниц, картинки, стили. -В tcpdump на внешнем интерфейсе eth_x виден только единственный и безответный SYN пакет, без сообщений ICMP. -ОС каким-то образом узнает о невозможности установить TCP соединение и выдает ошибку. -Если выполнять подключение с клиента, то SYN пропадают, соединение не устанавливается. -ОС клиента проводит ретрансмиссию, и с какого-то раза подключение удается. -Поэтому без tcp проксирования в этой ситуации сайты тупят, но загружаются, а с проксированием -подключение выполняется, но вскоре сбрасывается без каких-либо данных, и броузеры не пытаются установить -его заново. Поэтому качество броузинга с tpws может быть хуже, но дело не в tpws. -Частота сбросов заметно возрастает, если запущен торент клиент, имеется много tcp соединений. -Однако, причина не в переполнении таблицы conntrack. Увеличение лимитов и очистка conntrack не помогают. -Предположительно эта особенность связана с обработкой пакетов сброса соединения в hardware offload. -Точного ответа на вопрос у меня нет. Если вы знаете - поделитесь, пожалуйста. -Чтобы не ухудшать качество броузинга, можно фильтровать заворот на tpws по ip фильтру. -Поддержка ipset отсутствует. Значит, все, что можно сделать - создать индивидуальные правила -на небольшое количество хостов. - -Некоторые наброски скриптов присутствуют в files/huawei. Не готовое решение ! Смотрите, изучайте, приспосабливайте. -Здесь можно скачать готовые полезные статические бинарики для arm, включая curl : https://github.com/bol-van/bins - - -FreeBSD, OpenBSD, MacOS ------------------------ - -Описано в docs/bsd.txt - - -Windows (WSL) -------------- - -tpws в режиме socks можно запускать и под более-менее современными билдами windows 10 и windows server -с установленным WSL. Совсем не обязательно устанавливать дистрибутив убунту, как вам напишут почти в каждой -статье про WSL, которую вы найдете в сети. tpws - статический бинарик, ему дистрибутив не нужен. - -Установить WSL : dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all -Скопировать на целевую систему binaries/x86_64/tpws_wsl.tgz. -Выполнить : wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz -Запустить : wsl --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 <параметры_дурения> -Прописать socks 127.0.0.1:1080 в броузер или другую программу. - -Удаление : wsl --unregister tpws - -Проверено на windows 10 build 19041 (20.04). - -ЗАМЕЧАНИЕ. Под Windows существует нативное решение GoodByeDPI, выполняющее дурение на пакетном уровне (по типу nfqws). - - -Другие прошивки ---------------- - -Для статических бинариков не имеет значения на чем они запущены : PC, android, приставка, роутер, любой другой девайс. -Подойдет любая прошивка, дистрибутив linux. Статические бинарики запустятся на всем. -Им нужно только ядро с необходимыми опциями сборки или модулями. -Но кроме бинариков в проекте используются еще и скрипты, в которых задействуются некоторые -стандартные программы. - -Основные причины почему нельзя просто так взять и установить эту систему на что угодно : - * отсутствие доступа к девайсу через shell - * отсутствие рута - * отсутствие раздела r/w для записи и энергонезависимого хранения файлов - * отсутствие возможности поставить что-то в автозапуск - * отсутствие cron - * неотключаемый flow offload или другая проприетарщина в netfilter - * недостаток модулей ядра или опций его сборки - * недостаток модулей iptables (/usr/lib/iptables/lib*.so) - * недостаток стандартных программ (типа ipset, curl) или их кастрированность (облегченная замена) - * кастрированный или нестандартный шелл sh - -Если в вашей прошивке есть все необходимое, то вы можете адаптировать zapret под ваш девайс в той или иной степени. -Может быть у вас не получится поднять все части системы, однако вы можете хотя бы попытаться -поднять tpws и завернуть на него через -j REDIRECT весь трафик на порт 80. -Если вам есть куда записать tpws, есть возможность выполнять команды при старте, то как минимум -это вы сделать сможете. Скорее всего поддержка REDIRECT в ядре есть. Она точно есть на любом роутере, -на других устройствах под вопросом. NFQUEUE, ipset на большинстве прошивок отсутствуют из-за ненужности. - -Пересобрать ядро или модули для него будет скорее всего достаточно трудно. -Для этого вам необходимо будет по крайней мере получить исходники вашей прошивки. -User mode компоненты могут быть привнесены относительно безболезненно, если есть место куда их записать. -Специально для девайсов, имеющих область r/w, существует проект entware. -Некоторые прошивки даже имеют возможность его облегченной установки через веб интерфейс. -entware содержит репозиторий user-mode компонент, которые устанавливаются в /opt. -С их помощью можно компенсировать недостаток ПО основной прошивки, за исключением ядра. - -Можно попытаться использовать sysv init script таким образом, как это описано в разделе -"Прикручивание к системе управления фаерволом или своей системе запуска". -В случае ругани на отсутствие каких-то базовых программ, их следует восполнить посредством entware. -Перед запуском скрипта путь к дополнительным программам должен быть помещен в PATH. - -Подробное описание настроек для других прошивок выходит за рамки данного проекта. - -Openwrt является одной из немногих относительно полноценных linux систем для embedded devices. -Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивки : - * полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть - * корень r/w. это практически уникальная особенность openwrt. заводские и большинство альтернативных прошивок - построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области - встроенной памяти, называемой nvram. не имеющие r/w корня системы сильно кастрированы. они не имеют - возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном - на чуть более продвинутого, чем обычно, пользователя и управление имеющимся функционалом через веб интерфейс, - но функционал фиксированно ограничен. альтернативные прошивки как правило могут монтировать r/w раздел - в какую-то область файловой системы, заводские обычно могут монтировать лишь флэшки, подключенные к USB, - и не факт, что есть поддержка unix файловых системы. может быть поддержка только fat и ntfs. - * возможность выноса корневой файловой системы на внешний носитель (extroot) или создания на нем оверлея (overlay) - * наличие менеджера пакетов opkg и репозитория софта - * flow offload предсказуемо, стандартно и выборочно управляем, а так же отключаем - * в репозитории есть все модули ядра, их можно доустановить через opkg. ядро пересобирать не нужно. - * в репозитории есть все модули iptables, их можно доустановить через opkg - * в репозитории есть огромное количество стандартных программ и дополнительного софта - * наличие SDK, позволяющего собрать недостающее - - -Обход блокировки через сторонний хост -------------------------------------- - -Если не работает автономный обход, приходится перенаправлять трафик через сторонний хост. -Предлагается использовать прозрачный редирект через socks5 посредством iptables+redsocks, либо iptables+iproute+vpn. -Настройка варианта с redsocks на openwrt описана в redsocks.txt. -Настройка варианта с iproute+wireguard - в wireguard_iproute_openwrt.txt. - - -Почему стоит вложиться в покупку VPS ------------------------------------- - -VPS - это виртуальный сервер. Существует огромное множество датацентров, предлагающих данную услугу. -На VPS могут выполняться какие угодно задачи. От простого веб сайта до навороченной системы собственной разработки. -Можно использовать VPS и для поднятия собственного vpn или прокси. -Сама широта возможных способов применения , распространенность услуги сводят к минимуму возможности -регуляторов по бану сервисов такого типа. Да, если введут белые списки, то решение загнется, но это будет уже другая -реальность, в которой придется изобретать иные решения. -Пока этого не сделали, никто не будет банить хостинги просто потому , что они предоставляют хостинг услуги. -Вы как индивидуум скорее всего никому не нужны. Подумайте чем вы отличаетесь от известного VPN провайдера. -VPN провайдер предоставляет _простую_ и _доступную_ услугу по обходу блокировок для масс. -Этот факт делает его первоочередной целью блокировки. РКН направит уведомление, после отказа сотрудничать -заблокирует VPN. Предоплаченная сумма пропадет. -У регуляторов нет и никогда не будет ресурсов для тотальной проверки каждого сервера в сети. -Возможен китайский расклад, при котором DPI выявляет vpn протоколы и динамически банит IP серверов, -предоставляющих нелицензированный VPN. Но имея знания, голову, вы всегда можете обфусцировать -vpn трафик или применить другие типы VPN, более устойчивые к анализу на DPI или просто менее широкоизвестные, -а следовательно с меньшей вероятностью обнаруживамые регулятором. -У вас есть свобода делать на вашем VPS все что вы захотите, адаптируясь к новым условиям. -Да, это потребует знаний. Вам выбирать учиться и держать ситуацию под контролем, когда вам ничего запретить -не могут, или покориться системе. - -VPS можно прибрести в множестве мест. Существуют специализированные на поиске предложений VPS порталы. -Например, вот этот : https://vps.today/ -Для персонального VPN сервера обычно достаточно самой минимальной конфигурации, но с безлимитным трафиком или -с большим лимитом по трафику (терабайты). Важен и тип VPS. Openvz подойдет для openvpn, но -вы не поднимете на нем wireguard, ipsec, то есть все, что требует kernel mode. -Для kernel mode требуется тип виртуализации, предполагающий запуск полноценного экземпляра ОС linux -вместе с ядром. Подойдут kvm, xen, hyper-v, vmware. - -По цене можно найти предложения, которые будут дешевле готовой VPN услуги, но при этом вы сам хозяин в своей лавке -и не рискуете попасть под бан регулятора, разве что "заодно" под ковровую бомбардировку с баном миллионов IP. -Кроме того, если вам совсем все кажется сложным, прочитанное вызывает ступор, и вы точно знаете, что ничего -из описанного сделать не сможете, то вы сможете хотя бы использовать динамическое перенаправление портов ssh -для получения шифрованного socks proxy и прописать его в броузер. Знания linux не нужны совсем. -Это вариант наименее напряжный для чайников, хотя и не самый удобный в использовании. +zapret v.51 + +English +------- + +For english version refer to docs/readme.eng.txt + +Для чего это надо +----------------- + +Автономное, без задействования сторонних серверов, средство противодействия DPI. +Может помочь обойти блокировки или замедление сайтов http(s), сигнатурный анализ tcp и udp протоколов, +например с целью блокировки VPN. + +Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под openwrt. +Поддерживаются традиционные Linux системы, FreeBSD, OpenBSD, частично MacOS. +В некоторых случаях возможна самостоятельная прикрутка решения к различным прошивкам. + +Как побыстрее начать +-------------------- + +Читайте docs/quick_start.txt + + +Как это работает +---------------- + +В самом простейшем случае вы имеете дело с пассивным DPI. Пассивный DPI может читать трафик +из потока, может инжектить свои пакеты, но не может блокировать проходящие пакеты. +Если запрос "плохой", пассивный DPI инжектит пакет RST, опционально дополняя его пакетом http redirect. +Если фейк пакет инжектится только для клиента, в этом случае можно обойтись командами iptables +для дропа RST и/или редиректа на заглушку по определенным условиям, которые нужно подбирать +для каждого провайдера индивидуально. Так мы обходим последствия срабатывания триггера запрета. +Если пассивный DPI направляет пакет RST в том числе и серверу, то вы ничего с этим не сможете сделать. +Ваша задача - не допустить срабатывания триггера запрета. Одними iptables уже не обойдетесь. +Этот проект нацелен именно на предотвращение срабатывания запрета, а не ликвидацию его последствий. + +Активный DPI ставится в разрез провода и может дропать пакеты по любым критериям, +в том числе распознавать TCP потоки и блокировать любые пакеты, принадлежащие потоку. + +Как не допустить срабатывания триггера запрета ? Послать то, на что DPI не расчитывает +и что ломает ему алгоритм распознавания запросов и их блокировки. + +Некоторые DPI не могут распознать http запрос, если он разделен на TCP сегменты. +Например, запрос вида "GET / HTTP/1.1\r\nHost: kinozal.tv......" +мы посылаем 2 частями : сначала идет "GET ", затем "/ HTTP/1.1\r\nHost: kinozal.tv.....". +Другие DPI спотыкаются, когда заголовок "Host:" пишется в другом регистре : например, "host:". +Кое-где работает добавление дополнительного пробела после метода : "GET /" => "GET /" +или добавление точки в конце имени хоста : "Host: kinozal.tv." + +Существует и более продвинутая магия, направленная на преодоление DPI на пакетном уровне. + +Подробнее про DPI : + https://habr.com/ru/post/335436 + https://geneva.cs.umd.edu/papers/geneva_ccs19.pdf + +Как это реализовать на практике в системе linux +----------------------------------------------- + +Если кратко, то варианты можно классифицировать по следующей схеме : + +1) Пассивный DPI, не отправляющий RST серверу. Помогут индивидуально настраиваемые под провайдера команды iptables. +На rutracker в разделе "обход блокировок - другие способы" по этому вопросу существует отдельная тема. +В данном проекте не рассматривается. Если вы не допустите срабатывание триггера запрета, то и не придется +бороться с его последствиями. +2) Модификация TCP соединения на уровне потока. Реализуется через proxy или transparent proxy. +3) Модификация TCP соединения на уровне пакетов. Реализуется через обработчик очереди NFQUEUE и raw сокеты. + +Для вариантов 2 и 3 реализованы программы tpws и nfqws соответственно. +Чтобы они работали, необходимо их запустить с нужными параметрами и перенаправить на них определенный трафик +средствами iptables или nftables. + + +Для перенаправления tcp соединения на transparent proxy используются команды следующего вида : + +проходящий трафик : +iptables -t nat -I PREROUTING -i <внутренний_интерфейс> -p tcp --dport 80 -j DNAT --to 127.0.0.127:988 +исходящий трафик : +iptables -t nat -I OUTPUT -o <внешний_интерфейс> -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988 + +DNAT на localhost работает в цепочке OUTPUT, но не работает в цепочке PREROUTING без включения параметра route_localnet : + +sysctl -w net.ipv4.conf.<внутренний_интерфейс>.route_localnet=1 + +Можно использовать "-j REDIRECT --to-port 988" вместо DNAT , однако в этом случае процесс transparent proxy +должен слушать на ip адресе входящего интерфейса или на всех адресах. Слушать на всех - не есть хорошо +с точки зрения безопасности. Слушать на одном (локальном) можно, но в случае автоматизированного +скрипта придется его узнавать, потом динамически вписывать в команду. В любом случае требуются дополнительные усилия. +Использование route_localnet тоже имеет потенциальные проблемы с безопасностью. Вы делаете доступным все, что висит +на 127.0.0.0/8 для локальной подсети <внутренний_интерфейс>. Службы обычно привязываются к 127.0.0.1, поэтому можно +средствами iptables запретить входящие на 127.0.0.1 не с интерфейса lo, либо повесить tpws на любой другой IP из +из 127.0.0.0/8, например на 127.0.0.127, и разрешить входящие не с lo только на этот IP. + +iptables -A INPUT ! -i lo -d 127.0.0.127 -j ACCEPT +iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j DROP + +Фильтр по owner необходим для исключения рекурсивного перенаправления соединений от самого tpws. +tpws запускается под пользователем "tpws", для него задается исключающее правило. + +tpws может использоваться в режиме socks proxy. В этом случае iptables не нужны, а нужно прописать socks +в настройки программы (например, броузера), с которой будем обходить блокировки. +transparent proxy отличается от socks именно тем, что в варианте transparent настраивать клиентские программы не нужно. + + +Для перенаправления на очередь NFQUEUE исходящего и проходящего в сторону внешнего интерфейса трафика используются +команды следующего вида : + +iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -j NFQUEUE --queue-num 200 --queue-bypass + + +Чтобы не трогать трафик на незаблокированные адреса, можно взять список заблокированных хостов, заресолвить его +в IP адреса и загнать в ipset zapret, затем добавить фильтр в команду : + +iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass + +DPI может ловить только первый http запрос, игнорируя последующие запросы в keep-alive сессии. +Тогда можем уменьшить нагрузку на проц, отказавшись от процессинга ненужных пакетов. + +iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass + +Фильтр по mark нужен для отсечения от очереди пакетов, сгенерированных внутри nfqws. +Если применяется фильтр по connbytes 1:4, то обязательно добавлять в iptables и фильтр по mark. Иначе возможно +перепутывание порядка следования пакетов, что приведет к неработоспособности метода. + + +Если ваше устройство поддерживает аппаратное ускорение (flow offloading, hardware nat, hardware acceleration), то iptables могут не работать. +При включенном offloading пакет не проходит по обычному пути netfilter. +Необходимо или его отключить, или выборочно им управлять. + +В новых ядрах (и в более старых, openwrt портировал изменение на 4.14) присутствует software flow offloading (SFO). +Пакеты, проходящие через SFO, так же проходят мимо большей части механизмов iptables. +При включенном SFO работает DNAT/REDIRECT (tpws). Эти соединения исключаются из offloading. +Однако, остальные соединения идут через SFO, потому NFQUEUE будет срабатывать только до помещения +соединения в flowtable. Практически это означает, что nfqws будет работать на window size changing, +но не будут работать опции по модификации содержимого пакетов. +Offload включается через специальный target в iptables "FLOWOFFLOAD". Не обязательно пропускать весь трафик через offload. +Можно исключить из offload соединения, которые должны попасть на tpws или nfqws. +openwrt не предусматривает выборочного управления offload. +Поэтому скрипты zapret поддерживают свою систему выборочного управления offload в openwrt. + + +Особенности применения ip6tables +-------------------------------- + +ip6tables работают почти точно так же, как и ipv4, но есть ряд важных нюансов. +В DNAT следует брать адрес --to в квадратные скобки. Например : + + ip6tables -t nat -I OUTPUT -o <внешний_интерфейс> -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to [::1]:988 + +Параметра route_localnet не существует для ipv6. +DNAT на localhost (::1) возможен только в цепочке OUTPUT. +В цепочке PREROUTING DNAT возможен на любой global address или на link local address того же интерфейса, +откуда пришел пакет. +NFQUEUE работает без изменений. + + +Особенности применения nftables +------------------------------- + +Более подробно преимущества и недостатки nftables применительно к данной системе описаны в docs/nftables_notes.txt +Если коротко, то в nftables невозможно работать с большими ip листами на системах с малым количеством RAM. +Остальные рассматриваемые здесь функции могут быть перенесены на nftables. + +Рекомендуется версия nft 1.0.2 или выше. + +Относительно старые версии ядра и/или утилиты nft могут вызывать ошибки. +В частности, на ubuntu 18.04 с ядром 4.15 будут проблемы. В 20.04 - работает. + + +Когда это работать не будет +--------------------------- + +* Если подменяется DNS. С этой проблемой легко справиться. +* Если блокировка осуществляется по IP. +* Если соединение проходит через фильтр, способный реконструировать TCP соединение, и который +следует всем стандартам. Например, нас заворачивают на squid. Соединение идет через полноценный стек tcpip +операционной системы, фрагментация отпадает сразу как средство обхода. Squid правильный, он все найдет +как надо, обманывать его бесполезно. +НО. Заворачивать на squid могут позволить себе лишь небольшие провайдеры, поскольку это очень ресурсоемко. +Большие компании обычно используют DPI, который расчитан на гораздо большую пропускную способность. +Может применяться комбинированный подход, когда на DPI заворачивают только IP из "плохого" списка, +и дальше уже DPI решает пропускать или нет. Так можно снизить нагрузку на DPI в десятки, если не сотни раз, +а следовательно не покупать очень дорогие решения, обойдясь чем-то существенно более дешевым. +Мелкие провайдеры могут покупать услугу фильтрации у вышестоящих, чтобы самим не морочиться, и +они уже будут применять DPI. + + +nfqws +----- + +Эта программа - модификатор пакетов и обработчик очереди NFQUEUE. +Для BSD систем существует адаптированный вариант - dvtws, собираемый из тех же исходников (см. bsd.txt). + + --debug=0|1 ; 1=выводить отладочные сообщения + --daemon ; демонизировать прогу + --pidfile= ; сохранить PID в файл + --user= ; менять uid процесса + --uid=uid[:gid] ; менять uid процесса + --qnum=N ; номер очереди N + --bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов + --bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов + --wsize=[:] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !) + --wssize=[:] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !) + --wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N + --ctrack-timeouts=S:E:F[:U] ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60 + --hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:". + --hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета + --hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase + --domcase ; домен после Host: сделать таким : TeSt.cOm + --dpi-desync=[,][, ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000 + --dpi-desync-ttl= ; установить ttl для десинхронизирующих пакетов + --dpi-desync-ttl6= ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl + --dpi-desync-fooling= ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum hopbyhop hopbyhop2 + --dpi-desync-retrans=0|1 ; (только для fake,rst,rstack) 0(default)=отправлять оригинал следом за фейком 1=дропать оригинал, заставляя ОС выполнять ретрансмиссию через 0.2 сек + --dpi-desync-repeats= ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты) + --dpi-desync-skip-nosni=0| 1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI + --dpi-desync-split-pos=<1..1500> ; (только для split*, disorder*) разбивать пакет на указанной позиции + --dpi-desync-badseq-increment= ; инкремент sequence number для badseq. по умолчанию -10000 + --dpi-desync-badack-increment= ; инкремент ack sequence number для badseq. по умолчанию -66000 + --dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных + --dpi-desync-fake-http=|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному w3.org + --dpi-desync-fake-tls=|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному w3.org + --dpi-desync-fake-unknown=|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт + --dpi-desync-fake-quic=|0xHEX ; файл, содержащий фейковый QUIC Initial + --dpi-desync-fake-dht=|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт + --dpi-desync-fake-unknown-udp=|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт + --dpi-desync-udplen-increment= ; насколько увеличивать длину udp пейлоада в режиме udplen + --dpi-desync-udplen-pattern=|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули + --dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N + --hostlist= ; применять дурение только к хостам из листа. может быть множество листов, они обьединяются. пустой обший лист = его отсутствие + --hostlist-exclude= ; не применять дурение к хостам из листа. может быть множество листов, они обьединяются + +Параметры манипуляции могут сочетаться в любых комбинациях. + +ЗАМЕЧАНИЕ. Параметр --wsize считается устаревшим и более не поддерживается в скриптах. +Функции сплита выполняются в рамках атаки десинхронизации. Это быстрее и избавляет от целого ряда недостатков wsize. + +АТАКА ДЕСИНХРОНИЗАЦИИ DPI +Суть ее в следующем. После выполнения tcp 3-way handshake идет первый пакет с данными от клиента. +Там обычно "GET / ..." или TLS ClientHello. Мы дропаем этот пакет, заменяя чем-то другим. +Это может быть поддельная версия с безобидным, но валидным запросом http или https (вариант fake), +пакет сброса соединения (варианты rst, rstack), разбитый на части оригинальный пакет с перепутанным +порядком следования сегментов + обрамление первого сегмента фейками (disorder), +то же самое без перепутывания порядка сегментов (split). +fakeknown отличается от fake тем, что применяется только к распознанному протоколу. +В литературе такие атаки еще называют TCB desynchronization и TCB teardown. +Надо, чтобы фейковые пакеты дошли до DPI, но не дошли до сервера. +На вооружении есть следующие возможности : установить низкий TTL, посылать пакет с инвалидной чексуммой, +добавлять tcp option "MD5 signature", испортить sequence numbers. Все они не лишены недостатков. + +* md5sig работает не на всех серверах. Пакеты с md5 обычно отбрасывают только linux. +* badsum не сработает, если ваше устройство за NAT, который не пропускает пакеты с инвалидной суммой. + Наиболее распространенная настройка NAT роутера в Linux их не пропускает. На Linux построено большинство + домашних роутеров. Непропускание обеспечивается так : настройка ядра sysctl по умолчанию + net.netfilter.nf_conntrack_checksum=1 заставляет conntrack проверять tcp и udp чексуммы входящих пакетов + и выставлять state INVALID для пакетов с инвалидной суммой. + Обычно в правилах iptables вставляется правило для дропа пакетов с состоянием INVALID в цепочке FORWARD. + Совместное сочетание этих факторов приводит к непрохождению badsum через такой роутер. + В openwrt из коробки net.netfilter.nf_conntrack_checksum=0, в других роутерах часто нет, + и не всегда это можно изменить. Чтобы nfqws мог работать через роутер, нужно на нем выставить указанное + значение sysctl в 0. nfqws на самом роутере будет работать и без этой настройки, потому что + чексумма локально созданных пакетов не проверяется никогда. + Если роутер за другим NAT, например провайдерским, и он не пропускает invalid packets + вы ничего не сможете с этим сделать. Но обычно провайдеры все же пропускают badsum. + На некоторых адаптерах/свитчах/драйверах принудительно включен rx-checksum offload, badsum пакеты отсекаются + еще до получения в ОС. В этом случае если что-то и можно сделать, то только модифицировать драйвер, + что представляется задачей крайне нетривиальной. Установлено, что так себя ведут некоторые роутеры на базе mediatek. + badsum пакеты уходят с клиентской ОС, но роутером не видятся в br-lan через tcpdump. + При этом если nfqws выполняется на самом роутере, обход может работать. badsum нормально уходят с внешнего интерфейса. +* Пакеты с badseq будут наверняка отброшены принимающим узлом, но так же и DPI, если он ориентируется + на sequence numbers. По умолчанию смещение seq выбирается -10000. Практика показала, что некоторые DPI + не пропускают seq вне определенного окна. Однако, такое небольшое смещение может вызвать проблемы + при существенной потоковой передаче и потере пакетов. Если вы используете --dpi-desync-any-protocol, + может понадобится установить badseq increment 0x80000000. Это обеспечит надежную гарантию, + что поддельный пакет не вклинится в tcp window на сервере. Так же было замечено, что badseq ломает логику + некоторых DPI при анализе http, вызывая зависание соединения. Причем на тех же DPI TLS с badseq работает нормально. +* TTL казалось бы - лучший вариант, но он требует индивидуальной настройки под каждого провайдера. + Если DPI находится дальше локальных сайтов провайдера, то вы можете отрезать себе доступ к ним. + Необходим ip exclude list, заполняемый вручную. Вместе с ttl можно применять md5sig. Это ничего не испортит, + зато дает неплохой шанс работы сайтов, до которых "плохой" пакет дойдет по TTL. + Если не удается найти автоматическое решение, воспользуйтесь файлом zapret-hosts-user-exclude.txt. + Некоторые стоковые прошивки роутеров фиксируют исходящий TTL, без отключения этой опции через них работать не будет. + КАКИМ СТОИТ ВЫБИРАТЬ TTL : найдите минимальное значение, при котором обход еще работает. + Это и будет номер хопа вашего DPI. +* hopbyhop относится только к ipv6. Добавляется ipv6 extenstion header "hop-by-hop options". + В варианте hopbyhop2 добавляются 2 хедера, что является нарушением стандарта и гарантированно отбрасывается + стеком протоколов во всех ОС. Один хедер hop-by-hop принимается всеми ОС, однако на некоторых каналах/провайдерах + такие пакеты могут фильтроваться и не доходить. Расчет идет на то, что DPI проанализирует пакет с hop-by-hop, + но он либо не дойдет до адресата всилу фильтров провайдера, либо будет отброшен сервером, потому что хедера два. + +Режимы дурения могут сочетаться в любых комбинациях. --dpi-desync-fooling берет множество значений через запятую. + +Для режимов fake, rst, rstack после фейка отправляем оригинальный пакет. Можно его отправить сразу следом за фейком, а можно его просто дропнуть. +Если его дропнуть, ОС выполнит ретрансмиссию. Первая ретрансмиссия случается через 0.2 сек, потом задержка увеличивается экспоненциально. +Задержка может дать надежную гарантию, что пакеты пойдут именно в нужном порядке и будут именно в нем обработаны на DPI. +По умолчанию используется первый вариант, т.к. он быстрее. +При использовании dpi-desync-retrans=1 обязательно вставлять ограничитель connbytes в iptables, иначе получим зацикливание. + +Режим disorder делит оригинальный пакет на 2 части и отправляет следующую комбинацию в указанном порядке : +1. 2-я часть пакета +2. поддельная 1-я часть пакета, поле данных заполнено нулями +3. 1-я часть пакета +4. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз. +Оригинальный пакет дропается всегда. Параметр --dpi-desync-split-pos позволяет указать байтовую позицию, на которой +происходит разбивка. По умолчанию - 2. Если позиция больше длины пакета, позиция выбирается 1. +Этой последовательностью для DPI максимально усложняется задача реконструкции начального сообщения, +по которому принимается решение о блокировке. Некоторым DPI хватит и tcp сегментов в неправильном порядке, +поддельные части сделаны для дополнительной надежности и более сложных алгоритмов реконструкции. +Режим disorder2 отключает отправку поддельных частей. + +Режим split очень похож на disorder, только нет изменения порядка следования сегментов : +1. поддельная 1-я часть пакета, поле данных заполнено нулями +2. 1-я часть пакета +3. поддельная 1-я часть пакета, поле данных заполнено нулями. отсылка 2-й раз. +4. 2-я часть пакета +Режим split2 отключает отправку поддельных частей. +Он может быть использован как более быстрая альтернатива --wsize. + +disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны. + +Режимы десинхронизации hopbyhop, destopt и ipfrag1 (не путать с fooling !) относятся только к ipv6 и заключается +в добавлении хедера "hop-by-hop options" , "destination options" или "fragment" во все пакеты, попадающие под десинхронизацию. +Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено +к пакетам максимального размера. Это имеет место при передаче больших сообщений. +В случае невозможности отослать пакет дурение будет отменено, пакет будет выслан в оригинале. +Расчет идет на то, что DPI увидит 0 в поле next header основного заголовка ipv6 и не будет скакать по +extension хедерам в поисках транспортного хедера. Таким образом не поймет, что это tcp или udp, и пропустит пакет +без анализа. Возможно, какие-то DPI на это купятся. +Может сочетаться с любыми режимами 2-й фазы, кроме варианта "ipfrag1+ipfrag2". +Например, "hopbyhop,split2" означает разбить tcp пакет на 2 сегмента, в каждый из них добавить hop-by-hop. +При "hopbyhop,ipfrag2" последовательность хедеров будет : ipv6,hop-by-hop,fragment,tcp/udp. +Режим "ipfrag1" может срабатывать не всегда без специальной подготовки. См. раздел "IP фрагментация". + +Есть DPI, которые анализируют ответы от сервера, в частности сертификат из ServerHello, где прописаны домены. +Подтверждением доставки ClientHello является ACK пакет от сервера с номером ACK sequence, соответствующим длине ClientHello+1. +В варианте disorder обычно приходит сперва частичное подтверждение (SACK), потом полный ACK. +Если вместо ACK или SACK идет RST пакет с минимальной задержкой, то DPI вас отсекает еще на этапе вашего запроса. +Если RST идет после полного ACK спустя задержку, равную примерно пингу до сервера, +тогда вероятно DPI реагирует на ответ сервера. +DPI может отстать от потока, если ClientHello его удовлетворил и не проверять ServerHello. +Тогда вам повезло. Вариант fake может сработать. +Если же он не отстает и упорно проверяет ServerHello, то можно попробовать заставить сервер высылать ServerHello частями +через параметр --wssize (см. conntrack). +Если и это не помогает, то сделать с этим что-либо вряд ли возможно без помощи со стороны сервера. +Лучшее решение - включить на сервере поддержку TLS 1.3. В нем сертификат сервера передается в зашифрованном виде. +Это рекомендация ко всем админам блокируемых сайтов. Включайте TLS 1.3. Так вы дадите больше возможностей преодолеть DPI. + +Хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello. +Субдомены учитываются автоматически. Поддерживаются листы gzip. + +iptables для задействования атаки на первый пакет данных : + +iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass + +Этот вариант применяем, когда DPI не следит за всеми запросами http внутри keep-alive сессии. +Если следит, направляем только первый пакет от https и все пакеты от http : + +iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass +iptables -t mangle -I POSTROUTING -o <внешний_интерфейс> -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass + +mark нужен, чтобы сгенерированный поддельный пакет не попал опять к нам на обработку. nfqws выставляет fwmark при его отсылке. +хотя nfqws способен самостоятельно различать помеченные пакеты, фильтр в iptables по mark нужен при использовании connbytes, +чтобы не допустить изменения порядка следования пакетов. Процессинг очереди - процесс отложенный. +Если ядро имеет пакеты на отсылку вне очереди - оно их отправляет незамедлительно. +Изменение правильного порядка следования пакетов при десинхронизации ломает всю идею. +При отсутствии ограничения на connbytes, атака будет работать и без фильтра по mark. +Но лучше его все же оставить для увеличения скорости. + +Почему --connbytes 1:4 : +1 - для работы методов десинхронизации 0-й фазы и wssize +2 - иногда данные идут в 3-м пакете 3-way handshake +3 - стандартная ситуация +4 - для надежности. на случай, если выполнялась одна ретрансмиссия + +КОМБИНИРОВАНИЕ МЕТОДОВ ДЕСИНХРОНИЗАЦИИ +В параметре dpi-desync можно указать до 3 режимов через запятую. +0 фаза предполагает работу на этапе установления соединения. Может быть synack. +На 0 фазу не действует фильтр по hostlist. +Последующие режимы отрабатывают на пакетах с данными. +Режим 1-й фазы может быть fake,rst,rstack. Режим 2-й фазы может быть disorder,disorder2,split,split2,ipfrag2. +Может быть полезно, когда у провайдера стоит не один DPI. + +РЕЖИМ SYNACK +В документации по geneva это называется "TCB turnaround". Попытка ввести DPI в заблуждение относительно +ролей клиента и сервера. +!!! Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством +и DPI нет NAT. Атака не сработает через NAT роутер, но может сработать с него. +Для реализации атаки в linux обязательно требуется отключить стандартное правило firewall, +дропающее инвалидные пакеты в цепочке OUTPUT. Например : -A OUTPUT -m state --state INVALID -j DROP +В openwrt можно отключить drop INVALID в OUTPUT и FORWARD через опцию в /etc/config/firewall : + +config zone + option name 'wan' + ......... + option masq_allow_invalid '1' + +К сожалению, отключить только в OUTPUT таким образом нельзя. Но можно сделать иначе. Вписать в /etc/firewall.user : + +iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT +ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT + +Лучше делать так, потому что отсутствие дропа INVALID в FORWARD может привести к нежелательным утечкам пакетов из LAN. +Если не принять эти меры, отсылка SYN,ACK сегмента вызовет ошибку и операция будет прервана. +Остальные режимы тоже не сработают. Если поймете, что вам synack не нужен, обязательно верните правило дропа INVALID. + +ВИРТУАЛЬНЫЕ МАШИНЫ +Изнутри VM от virtualbox и vmware в режиме NAT не работают многие техники пакетной магии nfqws. +Принудительно заменяется ttl, не проходят фейк пакеты. Необходимо настроить сеть в режиме bridge. + +CONNTRACK +nfqws оснащен ограниченной реализацией слежения за состоянием tcp соединений (conntrack). +Он включается для реализации некоторых методов противодействия DPI. +На текущий момент это параметры --wssize и --dpi-desync-cutoff. +conntrack способен следить за фазой соединения : SYN,ESTABLISHED,FIN , количеством пакетов в каждую сторону, +sequence numbers. conntrack способен "кормиться" пакетами в обе или только в одну сторону. +Соединение попадает в таблицу при обнаружении пакетов с выставленными флагами SYN или SYN,ACK. +Поэтому если необходим conntrack, в правилах перенаправления iptables соединение должно идти на nfqws с самого первого +пакета, хотя затем может обрываться по фильтру connbytes. +Для UDP инициатором попадания в таблицу является первый UDP пакет. Он же и определяет направление потока. +Считается, что первый UDP пакет исходит от клиента к серверу. Далее все пакеты с совпадающими +src_ip,src_port,dst_ip,dst_port считаются принадлежащими этому потоку до истечения времени неактивности. +conntrack - простенький, он не писался с учетом всевозможных атак на соединение, он не проверяет +пакеты на валидность sequence numbers или чексумму. Его задача - лишь обслуживание нужд nfqws, он обычно +кормится только исходящим трафиком, потому нечувствителен к подменам со стороны внешней сети. +Соединение удаляется из таблицы, как только отпадает нужда в слежении за ним или по таймауту неактивности. +Существуют отдельные таймауты на каждую фазу соединения. Они могут быть изменены параметром --ctrack-timeouts. + +--wssize позволяет изменить с клиента размер tcp window для сервера, чтобы он послал следующие ответы разбитыми на части. +Чтобы это подействовало на все серверные ОС, необходимо менять window size в каждом исходящем с клиента пакете до отсылки сообщения, +ответ на который должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы +знать когда надо остановиться. Если не остановиться и все время устанавливать низкий wssize, скорость упадет катастрофически. +В linux это может быть купировано через connbytes, но в BSD системах такой возможности нет. +В случае http(s) останавливаемся сразу после отсылки первого http запроса или TLS ClientHello. +Если вы имеете дело с не http(s), то вам потребуется параметр --wssize-cutoff. Он устанавливает предел, с которого действие +wssize прекращается. Префикс d перед номером означает учитывать только пакеты с data payload, префикс s - relative sequence number, +проще говоря количество переданных клиентом байтов + 1. +Если проскочит пакет с http request или TLS ClientHello, действие wssize прекращается сразу же, не дожидаясь wssize-cutoff. +Если ваш протокол склонен к долгому бездействию, следует увеличить таймаут фазы ESTABLISHED через параметр --ctrack-timeouts. +Таймаут по умолчанию низкий - всего 5 минут. +Не забывайте, что nfqws кормится приходящими на него пакетами. Если вы ограничили поступление пакетов через connbytes, +то в таблице могут остаться повисшие соединения в фазе ESTABLISHED, которые отвалятся только по таймауту. +Для диагностики состояния conntrack пошлите сигнал SIGUSR1 процессу nfqws : killall -SIGUSR1 nfqws. +Текущая таблица будет выведена nfqws в stdout. + +Обычно в SYN пакете клиент отсылает кроме window size еще и TCP extension "scaling factor". +scaling factor представляет из себя степень двойки, на которую умножается window size : 0=>1, 1=>2, 2=>4, ..., 8=>256, ... +В параметре wssize scaling factor указывается через двоеточие. +Scaling factor может только снижаться, увеличение заблокировано, чтобы не допустить превышение размера окна со стороны сервера. +Для принуждения сервера к фрагментации ServerHello, чтобы избежать просекание имени сервера из сертификата сервера на DPI, +лучше всего использовать --wssize=1:6 . Основное правило - делать scale_factor как можно больше, чтобы после восстановления +window size итоговый размер окна стал максимально возможным. Если вы сделаете 64:0, будет очень медленно. +С другой стороны нельзя допустить, чтобы ответ сервера стал достаточно большим, чтобы DPI нашел там искомое. + +На --wssize не влияет фильтр hostlist, поскольку он действует с самого начала соединения, когда еще нельзя +принять решение о попадании в лист. +--wssize может замедлять скорость и/или увеличивать время ответа сайтов, поэтому если есть другие работающие способы +обхода DPI, лучше применять их. + +--dpi-desync-cutoff позволяет задать предел, при достижении которого прекращается применение dpi-desync. +Доступны префиксы n,d,s по аналогии с --wssize-cutoff. +Полезно совместно с --dpi-desync-any-protocol=1. +На склонных к бездействию соединениях следует изменить таймауты conntrack. +Если соединение выпало из conntrack и задана опция --dpi-desync-cutoff, dpi desync применяться не будет. + +ПОДДЕРЖКА UDP +Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip. +Для UDP действуют только режимы десинхронизации fake,hopbyhop,destopt,ipfrag1,ipfrag2,udplen,tamper. +Возможно сочетание fake,hopbyhop,destopt с ipfrag2, fake,fakeknown с udplen и tamper. +udplen увеличивает размер udp пакета на указанное в --dpi-desync-udplen-increment количество байтов. +Паддинг заполняется нулями по умолчанию, но можно задать свой паттерн. +Предназначено для обмана DPI, ориентирующегося на размеры пакетов. +Может сработать, если пользовательсткий протокол не привязан жестко к размеру udp пейлоада. +Режим tamper означает модификацию пакетов известных протоколов особенным для протокола образом. +На текущий момент работает только с DHT. +Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр +--hostlist будет работать. +Определяются пакеты wireguard handshake initiation и DHT (начинается с 'd1', кончается 'e'). +Для десинхронизации других протоколов обязательно указывать --dpi-desync-any-protocol. +Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp +можно изменить 4-м параметром в --ctrack-timeouts. +Атака fake полезна только для stateful DPI, она бесполезна для анализа на уровне отдельных пакетов. +По умолчанию fake наполнение - 64 нуля. Можно указать файл в --dpi-desync-fake-unknown-udp. + +IP ФРАГМЕНТАЦИЯ +В современной сети с этом все очень плохо. Фрагментированные пакеты застревают по пути, часто отбрасываются. +Иногда доходят. Иногда то доходят, то не доходят. Может зависеть от версии ipv4/ipv6. +Роутеры на базе linux могут самопроизвольно собирать или перефрагментировать пакеты. +Позиция фрагментации задается отдельно для tcp и udp. По умолчанию 24 и 8 соответственно, должна быть кратна 8. +Смещение считается с транспортного заголовка. + +Существует ряд моментов вокруг работы с фрагментами на Linux, без понимания которых может ничего не получиться. + +ipv4 : Linux дает отсылать ipv4 фрагменты, но стандартные настройки iptables в цепочке OUTPUT могут вызывать ошибки отправки. + +ipv6 : Нет способа для приложения гарантированно отослать фрагменты без дефрагментации в conntrack. +На разных системах получается по-разному. Где-то нормально уходят, где-то пакеты дефрагментируются. +Для ядер <4.16 похоже, что нет иного способа решить эту проблему, кроме как выгрузить модуль nf_conntrack, +который подтягивает зависимость nf_defrag_ipv6. Он то как раз и выполняет дефрагментацию. +Для ядер 4.16+ ситуация чуть лучше. Из дефрагментации исключаются пакеты в состоянии NOTRACK. +Чтобы не загромождать описание, смотрите пример решения этой проблемы в blockcheck.sh. + +Иногда требуется подгружать модуль ip6table_raw с параметром raw_before_defrag=1. +В openwrt параметры модулей указываются через пробел после их названий в файлах /etc/modules.d. +В традиционных системах посмотрите используется ли iptables-legacy или iptables-nft. Если legacy, то нужно создать файл +/etc/modprobe.d/ip6table_raw.conf с содержимым : +options ip6table_raw raw_before_defrag=1 +В некоторых традиционных дистрибутивах можно изменить текущий ip6tables через : update-alternatives --config ip6tables +Если вы хотите оставаться на iptables-nft, вам придется пересобрать патченную версию. Патч совсем небольшой. +В nft.c найдите фрагмент : + { + .name = "PREROUTING", + .type = "filter", + .prio = -300, /* NF_IP_PRI_RAW */ + .hook = NF_INET_PRE_ROUTING, + }, + { + .name = "OUTPUT", + .type = "filter", + .prio = -300, /* NF_IP_PRI_RAW */ + .hook = NF_INET_LOCAL_OUT, + }, +и замените везде -300 на -450. + +Это нужно сделать вручную, никакой автоматики в blockcheck.sh нет. + +Либо можно раз и навсегда избавиться от этой проблемы, используя nftables. Там можно создать netfilter hook +с любым приоритетом. Используйте приоритет -401 и ниже. + +При использовании iptables и NAT, похоже, что нет способа прицепить обработчик очереди после NAT. +MASQUERADE является финальным таргетом, после него NFQUEUE не срабатывает. +Пакет попадает в nfqws с source адресом внутренней сети, затем фрагментируется и уже не обрабатывается NAT. +Так и уходит во внешюю сеть с src ip 192.168.x.x. Следовательно, метод не срабатывает. +Видимо единственный рабочий метод - отказаться от iptables и использовать nftables. +Хук должен быть с приоритетом 101 или выше. + +tpws +----- + +tpws - это transparent proxy. + --debug=0|1|2 ; Количество буковок в output : 0(default)=тихо, 1=подробно, 2=отладка + --daemon ; демонизировать прогу + --pidfile= ; сохранить PID в файл + --user= ; менять uid процесса + --uid=uid[:gid] ; менять uid процесса + --bind-addr ; на каком адресе слушать. может быть ipv4 или ipv6 адрес + ; если указан ipv6 link local, то требуется указать с какого он интерфейса : fe80::1%br-lan + --bind-linklocal=no|unwanted|prefer|force + ; no : биндаться только на global ipv6 + ; unwanted (default) : предпочтительно global, если нет - LL + ; prefer : предпочительно LL, если нет - global + ; force : биндаться только на LL + --bind-iface4= ; слушать на первом ipv4 интерфейса iface + --bind-iface6= ; слушать на первом ipv6 интерфейса iface + --bind-wait-ifup= ; ждать до N секунд появления и поднятия интерфейса + --bind-wait-ip= ; ждать до N секунд получения IP адреса (если задан --bind-wait-ifup - время идет после поднятия интерфейса) + --bind-wait-ip-linklocal= + ; имеет смысл только при задании --bind-wait-ip + ; --bind-linklocal=unwanted : согласиться на LL после N секунд + ; --bind-linklocal=prefer : согласиться на global address после N секунд + --bind-wait-only ; подождать все бинды и выйти. результат 0 в случае успеха, иначе не 0. + --socks ; вместо прозрачного прокси реализовать socks4/5 proxy + --no-resolve ; запретить ресолвинг имен через socks5 + --port= ; на каком порту слушать + --maxconn= ; максимальное количество соединений от клиентов к прокси + --maxfiles= ; макс количество файловых дескрипторов (setrlimit). мин требование (X*connections+16), где X=6 в tcp proxy mode, X=4 в режиме тамперинга. + ; стоит сделать запас с коэффициентом как минимум 1.5. по умолчанию maxfiles (X*connections)*1.5+16 + --max-orphan-time=; если вы запускаете через tpws торрент-клиент с множеством раздач, он пытается установить очень много исходящих соединений, + ; большая часть из которых отваливается по таймату (юзера сидят за NAT, firewall, ...) + ; установление соединения в linux может длиться очень долго. локальный конец отвалился, перед этим послав блок данных, + ; tpws ждет подключения удаленного конца, чтобы отослать ему этот блок, и зависает надолго. + ; настройка позволяет сбрасывать такие подключения через N секунд, теряя блок данных. по умолчанию 5 сек. 0 означает отключить функцию + ; эта функция не действует на успешно подключенные ранее соединения + + --local-rcvbuf= ; SO_RCVBUF для соединений client-proxy + --local-sndbuf= ; SO_SNDBUF для соединений client-proxy + --remote-rcvbuf= ; SO_RCVBUF для соединений proxy-target + --remote-sndbuf= ; SO_SNDBUF для соединений proxy-target + --skip-nodelay ; не устанавливать в исходящих соединения TCP_NODELAY. несовместимо со split. + + --split-http-req=method|host ; способ разделения http запросов на сегменты : около метода (GET,POST) или около заголовка Host + --split-pos= ; делить все посылы на сегменты в указанной позиции. единственная опция, работающая на не-http. при указании split-http-req он имеет преимущество на http. + --split-any-protocol ; применять split-pos к любым пакетам. по умолчанию - только к http и TLS ClientHello + --disorder ; путем манипуляций с сокетом вынуждает отправлять первым второй сегмент разделенного запроса + --hostcase ; менять регистр заголовка "Host:". по умолчанию на "host:". + --hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase + --hostdot ; добавление точки после имени хоста : "Host: kinozal.tv." + --hosttab ; добавление табуляции после имени хоста : "Host: kinozal.tv\t" + --hostnospace ; убрать пробел после "Host:" + --hostpad= ; добавить паддинг-хедеров общей длиной перед Host: + --domcase ; домен после Host: сделать таким : TeSt.cOm + --methodspace ; добавить пробел после метода : "GET /" => "GET /" + --methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /" + --unixeol ; конвертировать 0D0A в 0A и использовать везде 0A + --tlsrec=sni ; разбивка TLS ClientHello на 2 TLS records. режем между 1 и 2 символами hostname в SNI. Если SNI нет - отмена. + --tlsrec-pos= ; разбивка TLS ClientHello на 2 TLS records. режем на указанной позиции, если длина слишком мелкая - на позиции 1. + --hostlist= ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются. + ; в файле должен быть хост на каждой строке. + ; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска. + ; по сигналу HUP список будет перечитан при следующем принятом соединении + ; список может быть запакован в gzip. формат автоматически распознается и разжимается + ; списков может быть множество, они обьединяются. пустой общий лист = его отсутствие + ; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello. + --hostlist-exclude= ; не применять дурение к доменам из листа. может быть множество листов, они обьединяются + + +Параметры манипуляции могут сочетаться в любых комбинациях. + +В случае http запроса split-http-req имеет преимущество над split-pos. +split-pos по умолчанию работает только на http и TLS ClientHello. +Чтобы он работал на любых пакетах, укажите --split-any-protocol. + +На прикладном уровне в общем случае нет гарантированного средства заставить ядро выплюнуть +блок данных, порезанным в определенном месте. ОС держит буфер отсылки (SNDBUF) у каждого сокета. +Если у сокета включена опция TCP_NODELAY и буфер пуст, то каждый send приводит к отсылке +отдельного ip пакета или группы пакетов, если блок не вмещается в один ip пакет. +Однако, если в момент send уже имеется неотосланный буфер, то ОС присоединит данные к нему, +никакой отсылки отдельным пакетом не будет. Но в этом случае и так нет никакой гарантии, +что какой-то блок сообщения пойдет в начале пакета, на что собственно и заточены DPI. +Разбиение будет производится согласно MSS, который зависит от MTU исходящего интерфейса. +Таким образом DPI, смотрящие в начало поля данных TCP пакета, будут поломаны в любом случае. +Протокол http относится к запрос-ответным протоколам. Новое сообщение посылается только тогда, +когда сервер получил запрос и полностью вернул ответ. Значит запрос фактически был не только отослан, +но и принят другой стороной, а следовательно буфер отсылки пуст, и следующие 2 send приведут +к отсылке сегментов данных разными ip пакетами. +Резюме : tpws гарантирует сплит только за счет раздельных вызовов send, что на практике +вполне достаточно для протоколов http(s). + +tpws может биндаться на множество интерфейсов и IP адресов (до 32 шт). +Порт всегда только один. +Параметры --bind-iface* и --bind-addr создают новый бинд. +Остальные параметры --bind-* относятся к последнему бинду. +Для бинда на все ipv4 укажите --bind-addr "0.0.0.0", на все ipv6 - "::". --bind-addr="" - биндаемся на все ipv4 и ipv6. +Выбор режима использования link local ipv6 адресов (fe80::/8) : +--bind-iface6 --bind-linklocal=no : сначала приватный адрес fc00::/7, затем глобальный адрес +--bind-iface6 --bind-linklocal=unwanted : сначала приватный адрес fc00::/7, затем глобальный адрес, затем link local. +--bind-iface6 --bind-linklocal=prefer : сначала link local, затем приватный адрес fc00::/7, затем глобальный адрес. +--bind-iface6 --bind-linklocal=force : только link local +Если не указано ни одного бинда, то создается бинд по умолчанию на все адреса всех интерфейсов. +Для бинда на конкретный link-local address делаем так : --bind-iface6=fe80::aaaa:bbbb:cccc:dddd%iface-name +Параметры --bind-wait* могут помочь в ситуациях, когда нужно взять IP с интерфейса, но его еще нет, он не поднят +или не сконфигурирован. +В разных системах события ifup ловятся по-разному и не гарантируют, что интерфейс уже получил IP адрес определенного типа. +В общем случае не существует единого механизма повеситься на событие типа "на интерфейсе X появился link local address". +Для бинда на известный ip, когда еще интерфейс не сконфигурирован, нужно делать так : --bind-addr=192.168.5.3 --bind-wait-ip=20 +В режиме transparent бинд возможен на любой несуществующий адрес, в режиме socks - только на существующий. + +Параметры rcvbuf и sndbuf позволяют установить setsockopt SO_RCVBUF SO_SNDBUF для локального и удаленного соединения. + +Если не указан ни один из параметров модификации содержимого, tpws работает в режиме "tcp proxy mode". +Он отличается тем, что в оба конца применяется splice для переброски данных из одного сокета в другой +без копирования в память процесса. Практически - это то же самое, но может быть чуть побыстрее. +TCP проксирование может быть полезно для обхода блокировок, когда DPI спотыкается на экзотических +хедерах IP или TCP. Вы вряд ли сможете поправить хедеры, исходящие от айфончиков и гаджетиков, +но на linux сможете влиять на них в какой-то степени через sysctl. +Когда соединение проходит через tpws, фактически прокси-сервер сам устанавливает подключение к удаленному +узлу от своего имени, и на это распространяются настройки системы, на которой работает прокси. +tpws можно использовать на мобильном устройстве, раздающем интернет на тарифе сотового оператора, +где раздача запрещена, в socks режиме даже без рута. Соединения от tpws неотличимы от соединений +с самого раздающего устройства. Отличить можно только по содержанию (типа обновлений windows). +Заодно можно и обойти блокировки. 2 зайца одним выстрелом. +Более подробную информацию по вопросу обхода ограничений операторов гуглите на 4pda.ru. + +Режим "--socks" не требует повышенных привилегий (кроме бинда на привилегированные порты 1..1023). +Поддерживаются версии socks 4 и 5 без авторизации. Версия протокола распознается автоматически. +Подключения к IP того же устройства, на котором работает tpws, включая localhost, запрещены. +socks5 позволяет удаленно ресолвить хосты (curl : --socks5-hostname firefox : socks_remote_dns=true). +tpws поддерживает эту возможность, однако используется блокирующий ресолвинг. Пока система +ресолвит хост (это может занять секунды), вся активность останавливается. +tpws полностью работает на асинхронных сокетах, но ресолвинг может попортить эту модель. +С ним возможны атаки DoS на tpws. Если tpws обслуживает множество клиентов, то из-за частого +ресолвинга качество обслуживания может существенно ухудшиться. +Если удаленный ресолвинг создает проблемы, настройте клиенты на локальный ресолвинг, включите опцию +--no-resolve на стороне tpws. + +Параметр --hostpad= добавляет паддинг-хедеров перед Host: на указанное количество байтов. +Если размер слишком большой, то идет разбивка на разные хедеры по 2K. +Общий буфер приема http запроса - 64K, больший паддинг не поддерживается, да и http сервера +такое уже не принимают. +Полезно против DPI, выполняющих реассемблинг TCP с ограниченным буфером. +Если техника работает, то после некоторого количества bytes http запрос начнет проходить до сайта. +Если при этом критический размер padding около MTU, значит скорее всего DPI не выполняет реассемблинг пакетов, и лучше будет использовать обычные опции --split-… +Если все же реассемблинг выполняется, то критический размер будет около размера буфера DPI. Он может быть 4K или 8K, возможны и другие значения. + +--disorder - это попытка симулировать режим disorder2 nfqws , используя особенности ОС по реализации stream сокетов. +Однако, в отличие от nfqws, здесь не требуются повышенные привилегии. +Реализовано это следующим образом. У сокета есть возможность выставить TTL. Все пакеты будут отправляться с ним. +Перед отправкой первого сегмента ставим TTL=1. Пакет будет дропнут на первом же роутере, он не дойдет ни до DPI, ни до сервера. +Затем возвращаем TTL в значение по умолчанию. ОС отсылает второй сегмент, и он уже доходит до сервера. +Сервер возвращает SACK, потому что не получил первый кусок, и ОС его отправляет повторно, но здесь уже мы ничего не делаем. +Этот режим работает как ожидается на Linux и MacOS. Однако, на FreeBSD и OpenBSD он работает не так хорошо. +Ядро этих ОС отсылает ретрансмиссию в виде полного пакета. Потому выходит, что до сервера идет сначала второй кусок, +а потом полный запрос без сплита. На него может отреагировать DPI штатным образом. +--disorder является дополнительным флагом к любому сплиту. Сам по себе он не делает ничего. + +--tlsrec и --tlsrec-pos позволяют внутри одного tcp сегмента разрезать TLS ClientHello на 2 TLS records. +--tlsrec=sni режет между 1 и 2 символами hostname в SNI, делая невозможным бинарный поиск паттерна без анализа структуры данных. +В случае отсутствия SNI разбиение отменяется. +--tlsrec-pos режет на указанной позиции. Если длина блока данных TLS меньше указанной позиции, режем на позиции 1. +Параметр сочетается с --split-pos. В этом случае происходит сначала разделение на уровне TLS record layer, потом на уровне TCP. +Самая изорщенная атака --tslrec, --split-pos и --disorder вместе. +--tlsrec ломает значительное количество сайтов. Криптобиблиотеки (openssl, ...) на оконечных http серверах без проблем +принимают разделенные tls сегменты, но мидлбоксы - не всегда. К мидлбоксам можно отнести CDN или системы ddos-защиты. +Поэтому применение --tlsrec без ограничителей вряд ли целесообразно. +В РФ --tlsrec обычно не работает с TLS 1.2, потому что цензор парсит сертификат сервера из ServerHello. +Работает только с TLS 1.3, поскольку там эта информация шифруется. +Впрочем, сейчас сайтов, не поддерживающих TLS 1.3, осталось немного. + +--skip-nodelay может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws. +Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения +подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз. + + +Способы получения списка заблокированных IP +------------------------------------------- + +!!! nftables не могут работать с ipset-ами. Собственный аналогичный механизм требует огромного количество RAM +!!! для загрузки больших листов. Например, для загона 100K записей в nfset не хватает даже 256 Mb. +!!! Если вам нужны большие листы на домашних роутерах, откатывайтесь на iptables+ipset. + +1) Внесите заблокированные домены в ipset/zapret-hosts-user.txt и запустите ipset/get_user.sh +На выходе получите ipset/zapret-ip-user.txt с IP адресами. + +Cкрипты с названием get_reestr_* оперируют дампом реестра заблокированных сайтов : + +2) ipset/get_reestr_resolve.sh получает список доменов от rublacklist и дальше их ресолвит в ip адреса +в файл ipset/zapret-ip.txt.gz. В этом списке есть готовые IP адреса, но судя во всему они там в точности в том виде, +что вносит в реестр РосКомПозор. Адреса могут меняться, позор не успевает их обновлять, а провайдеры редко +банят по IP : вместо этого они банят http запросы с "нехорошим" заголовком "Host:" вне зависимости +от IP адреса. Поэтому скрипт ресолвит все сам, хотя это и занимает много времени. +Используется мультипоточный ресолвер mdig (собственная разработка). + +3) ipset/get_reestr_preresolved.sh. то же самое, что и 2), только берется уже заресолвленый список +со стороннего ресурса. + +4) ipset/get_reestr_preresolved_smart.sh. то же самое, что и 5), с добавлением всего диапазона некоторых +автономных систем (прыгающие IP адреса из cloudflare, facebook, ...) и некоторых поддоменов блокируемых сайтов + +Cкрипты с названием get_antifilter_* оперируют списками адресов и масок подсетей с сайтов antifilter.network и antifilter.download : + +5) ipset/get_antifilter_ip.sh. получает лист https://antifilter.download/list/ip.lst. + +6) ipset/get_antifilter_ipsmart.sh. получает лист https://antifilter.network/download/ipsmart.lst. +умная суммаризация отдельных адресов из ip.lst по маскам от /32 до /22 + +7) ipset/get_antifilter_ipsum.sh. получает лист https://antifilter.download/list/ipsum.lst. +суммаризация отдельных адресов из ip.lst по маске /24 + +8) ipset/get_antifilter_ipresolve.sh. получает лист https://antifilter.download/list/ipresolve.lst. +пре-ресолвленный список, аналогичный получаемый при помощи get_reestr_resolve. только ipv4. + +9) ipset/get_antifilter_allyouneed.sh. получает лист https://antifilter.download/list/allyouneed.lst. +Суммарный список префиксов, созданный из ipsum.lst и subnet.lst. + +Все варианты рассмотренных скриптов автоматически создают и заполняют ipset. +Варианты 2-9 дополнительно вызывают вариант 1. + +10) ipset/get_config.sh. этот скрипт вызывает то, что прописано в переменной GETLIST из файла config +Если переменная не определена, то ресолвятся лишь листы для ipset nozapret/nozapret6. + +Листы РКН все время изменяются. Возникают новые тенденции. Требования к RAM могут меняться. +Поэтому необходима нечастая, но все же регулярная ревизия что же вообще у вас происходит на роутере. +Или вы можете узнать о проблеме лишь когда у вас начнет постоянно пропадать wifi, и вам придется +его перезагружать каждые 2 часа (метод кувалды). + +Самые щадящие варианты по RAM - get_antifilter_allyouneed.sh, get_antifilter_ipsum.sh. + +Листы zapret-ip.txt и zapret-ipban.txt сохраняются в сжатом виде в файлы .gz. +Это позволяет снизить их размер во много раз и сэкономить место на роутере. +Отключить сжатие листов можно параметром конфига GZIP_LISTS=0. + +На роутерах не рекомендуется вызывать эти скрипты чаще раза за 2 суток, поскольку сохранение идет +либо во внутреннюю флэш память роутера, либо в случае extroot - на флэшку. +В обоих случаях слишком частая запись может убить флэшку, но если это произойдет с внутренней +флэш памятью, то вы просто убьете роутер. + +Принудительное обновление ipset выполняет скрипт ipset/create_ipset.sh. +Если передан параметр "no-update", скрипт не обновляет ipset, а только создает его при его отсутствии и заполняет. +Это полезно, когда могут случиться несколько последовательных вызовов скрипта. Нет смысла несколько раз перезаполнять +ipset, это длительная операция на больших листах. Листы можно обновлять раз в несколько суток, и только тогда +вызывать create_ipset без параметра "no-update". Во всех остальных случаях стоит применять "no-update". + +Список РКН уже достиг внушительных размеров в сотни тысяч IP адресов. Поэтому для оптимизации ipset +применяется утилита ip2net. Она берет список отдельных IP адресов и пытается интеллектуально создать из него подсети для сокращения +количества адресов. ip2net отсекает неправильные записи в листах, гарантируя осутствие ошибок при их загрузке. +ip2net написан на языке C, поскольку операция ресурсоемкая. Иные способы роутер может не потянуть. + +Можно внести список доменов в ipset/zapret-hosts-user-ipban.txt. Их ip адреса будут помещены +в отдельный ipset "ipban". Он может использоваться для принудительного завертывания всех +соединений на прозрачный proxy "redsocks" или на VPN. + +IPV6 : если включен ipv6, то дополнительно создаются листы с таким же именем, но с "6" на конце перед расширением. +zapret-ip.txt => zapret-ip6.txt +Создаются ipset-ы zapret6 и ipban6. +Листы с antifilter не содержат список ipv6 адресов. + +СИСТЕМА ИСКЛЮЧЕНИЯ IP. Все скрипты ресолвят файл zapret-hosts-user-exclude.txt, создавая zapret-ip-exclude.txt и zapret-ip-exclude6.txt. +Они загоняются в ipset-ы nozapret и nozapret6. Все правила, создаваемые init скриптами, создаются с учетом этих ipset. +Помещенные в них IP не участвуют в процессе. +zapret-hosts-user-exclude.txt может содержать домены, ipv4 и ipv6 адреса или подсети. + +FreeBSD. Скрипты ipset/*.sh работают так же на FreeBSD. Вместо ipset они создают lookup таблицы ipfw с аналогичными именами. +ipfw таблицы в отличие от ipset могут содержать как ipv4, так и ipv6 адреса и подсети в одной таблице, поэтому разделения нет. + +Параметр конфига LISTS_RELOAD задает произвольную команду для перезагрузки листов. +Это особенно полезно на BSD системах с PF. +LISTS_RELOAD=- отключает перезагрузку листов. + + +ip2net +------ + +Утилита ip2net предназначена для преобразования ipv4 или ipv6 списка ip в список подсетей +с целью сокращения размера списка. Входные данные берутся из stdin, выходные выдаются в stdout. + + -4 ; лист - ipv4 (по умолчанию) + -6 ; лист - ipv6 + --prefix-length=min[-max] ; диапазон рассматриваемых длин префиксов. например : 22-30 (ipv4), 56-64 (ipv6) + --v4-threshold=mul/div ; ipv4 : включать подсети, в которых заполнено по крайней мере mul/div адресов. например : 3/4 + --v6-threshold=N ; ipv6 : минимальное количество ip для создания подсети + +В списке могут присутствовать записи вида ip/prefix и ip1-ip2. Такие записи выкидываются в stdout без изменений. +Они принимаются командой ipset. ipset умеет для листов hash:net из ip1-ip2 делать оптимальное покрытие ip/prefix. +ipfw из FreeBSD понимает ip/prefix, но не понимает ip1-ip2. +ip2net фильтрует входные данные, выкидывая неправильные IP адреса. + +Выбирается подсеть, в которой присутствует указанный минимум адресов. +Для ipv4 минимум задается как процент от размера подсети (mul/div. например, 3/4), для ipv6 минимум задается напрямую. + +Размер подсети выбирается следующим алгоритмом : +Сначала в указанном диапазоне длин префиксов ищутся подсети, в которых количество адресов - максимально. +Если таких сетей найдено несколько, берется наименьшая сеть (префикс больше). +Например, заданы параметры v6_threshold=2 prefix_length=32-64, имеются следующие ipv6 : +1234:5678:aaaa::5 +1234:5678:aaaa::6 +1234:5678:aaac::5 +Результат будет : +1234:5678:aaa8::/45 +Эти адреса так же входят в подсеть /32. Однако, нет смысла проходиться ковровой бомбардировкой, +когда те же самые адреса вполне влезают в /45 и их ровно столько же. +Если изменить v6_threshold=4, то результат будет : +1234:5678:aaaa::5 +1234:5678:aaaa::6 +1234:5678:aaac::5 +То есть ip не объединятся в подсеть, потому что их слишком мало. +Если изменить prefix_length=56-64, результат будет : +1234:5678:aaaa::/64 +1234:5678:aaac::5 + +Требуемое процессорное время для вычислений сильно зависит от ширины диапазона длин префиксов, размера искомых подсетей и длины листа. +Если ip2net думает слишком долго, не используйте слишком большие подсети и уменьшите диапазон длин префиксов. +Учтите, что арифметика mul/div - целочисленная. При превышении разрядной сетки 32 bit результат непредсказуем. +Не надо делать такое : 5000000/10000000. 1/2 - гораздо лучше. + + +Фильтрация по именам доменов +---------------------------- + +Альтернативой ipset является использование tpws или nfqws со списком доменов. +Оба демона принимают неограниченное количество листов include (--hostlist) и exclude (--hostlist-exclude). +Все листы одного типа обьединяются, и таким образом остаются только 2 листа. +Прежде всего проверяется exclude list. При вхождении в него происходит отказ от дурения. +Далее при наличии include list проверяется домен на вхождение в него. При невхождении в список отказ от дурения. +Пустой список приравнивается к его отсутствию. +В иных случаях происходит дурение. +Нет ни одного списка - дурение всегда. +Есть только exclude список - дурение всех, кроме. +Есть только include список - дурение только их. +Есть оба - дурение только include, кроме exclude. + +В системе запуска это обыграно следующим образом. +Присутствуют 2 include списка : +ipset/zapret-hosts-users.txt.gz или ipset/zapret-hosts-users.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 + +При режиме фильтрации MODE_FILTER=hostlist система запуска передает nfqws или tpws все листы, файлы которых присутствуют. +Если вдруг листы include присутствуют, но все они пустые, то работа аналогична отсутствию include листа. +Файл есть, но не смотря на это дурится все, кроме exclude. +Если вам нужен именно такой режим - не обязательно удалять zapret-hosts-users.txt. Достаточно сделать его пустым. + +Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает. + +Список доменов РКН может быть получен скриптами ipset/get_reestr_hostlist.sh или ipset/get_antizapret_domains.sh +- кладется в ipset/zapret-hosts.txt.gz. + +Чтобы обновить списки, перезапускать nfqws или tpws не нужно. Обновляете файлы, затем даете сигнал HUP. +По HUP листы будут перечитаны. Если вдруг какого-то листа не окажется, процесс завершится с ошибкой. +Скрипты получения листов из ipset сами выдают HUP в конце. + +При фильтрации по именам доменов демон должен запускаться без фильтрации по ipset. +tpws и nfqws решают нужно ли применять дурение в зависимости от хоста, полученного из протокола прикладного уровня (http, tls, quic). +При использовании больших списков, в том числе списка РКН, оцените объем RAM на роутере ! +Если после запуска демона RAM под завязку или случаются oom, значит нужно отказаться от таких больших списков. + + +Проверка провайдера +------------------- + +Перед настройкой нужно провести исследование какую бяку устроил вам ваш провайдер. + +Нужно выяснить не подменяет ли он DNS и какой метод обхода DPI работает. +В этом вам поможет скрипт blockcheck.sh. + +Если DNS подменяется, но провайдер не перехватывает обращения к сторонним DNS, поменяйте DNS на публичный. +Например : 8.8.8.8, 8.8.4.4, 1.1.1.1, 1.0.0.1, 9.9.9.9 +Если DNS подменяется и провайдер перехватывает обращения к сторонним DNS, настройте dnscrypt. +Еще один эффективный вариант - использовать ресолвер от yandex 77.88.8.88 на нестандартном порту 1253. +Многие провайдеры не анализируют обращения к DNS на нестандартных портах. + +Следует прогнать blockcheck по нескольким заблокированным сайтам и выявить общий характер блокировок. +Разные сайты могут быть заблокированы по-разному, нужно искать такую технику, которая работает на большинстве. +Чтобы записать вывод blockcheck.sh в файл, выполните : ./blockcheck.sh | tee /tmp/blockcheck.txt + +Проанализируйте какие методы дурения DPI работают, в соответствии с ними настройте /opt/zapret/config. + +Имейте в виду, что у провайдеров может быть несколько DPI или запросы могут идти через разные каналы +по методу балансировки нагрузки. Балансировка может означать, что на разных ветках разные DPI или +они находятся на разных хопах. Такая ситуация может выражаться в нестабильности работы обхода. +Дернули несколько раз curl. То работает, то connection reset или редирект. blockcheck.sh выдает +странноватые результаты. То split работает на 2-м. хопе, то на 4-м. Достоверность результата вызывает сомнения. +В этом случае задайте несколько повторов одного и того же теста. Тест будет считаться успешным только, +если все попытки пройдут успешно. + + +Выбор параметров +---------------- + +Файл /opt/zapret/config используется различными компонентами системы и содержит основные настройки. +Его нужно просмотреть и при необходимости отредактировать. + +На linux системах можно выбрать использовать iptables или nftables. +По умолчанию на традиционных linux выбирается nftables, если установлен nft. +На openwrt по умолчанию выбирается nftables на новых версиях с firewall4. + +FWTYPE=iptables + +Основной режим : +tpws - tpws в режиме transparent +tpws-socks - tpws в режиме socks + вешается на localhost и LAN интерфейс (если задан IFACE_LAN или если система - OpenWRT). порт 988 +nfqws - nfqws +filter - только заполнить ipset или загрузить hostlist +custom - нужно самому запрограммировать запуск демонов в init скрипте и правила iptables + +MODE=tpws + +Применять ли дурение к HTTP : + +MODE_HTTP=1 + +Применять ли дурение к последовательным http запросам в одном tcp соединении (http keeaplive). +Относится только к nfqws. Выключение данной функции способно сэкономить загрузку процессора. +tpws всегда работает с http keepalive + +MODE_HTTP_KEEPALIVE=0 + +Применять ли дурение к HTTPS : + +MODE_HTTPS=1 + +Применять ли дурение к QUIC : + +MODE_QUIC=0 + +Режим фильтрации хостов : +none - применять дурение ко всем хостам +ipset - ограничить дурение ipset-ом zapret/zapret6 +hostlist - ограничить дурение списком хостов из файла + +MODE_FILTER=none + +Опции tpws : + +TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3" + +Опции nfqws для атаки десинхронизации DPI : + +DESYNC_MARK=0x40000000 +NFQWS_OPT_DESYNC="--dpi-desync=fake --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" + +Задание раздельных опций nfqws для http и https и для версий ip протоколов 4,6 : + +NFQWS_OPT_DESYNC_HTTP="--dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" +NFQWS_OPT_DESYNC_HTTPS="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=0 --dpi-desync-fooling=badsum" +NFQWS_OPT_DESYNC_HTTP6="--dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" +NFQWS_OPT_DESYNC_HTTPS6="--wssize=1:6 --dpi-desync=split --dpi-desync-ttl=5 --dpi-desync-fooling=none" + +Если какая-то из переменных NFQWS_OPT_DESYNC_HTTP/NFQWS_OPT_DESYNC_HTTPS не определена, +берется значение NFQWS_OPT_DESYNC. +Если какая-то из переменных NFQWS_OPT_DESYNC_HTTP6/NFQWS_OPT_DESYNC_HTTPS6 не определена, +берется значение NFQWS_OPT_DESYNC_HTTP/NFQWS_OPT_DESYNC_HTTPS. + +Опции дурения для QUIC : +NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake" +NFQWS_OPT_DESYNC_QUIC6="--dpi-desync=hopbyhop" +Если NFQWS_OPT_DESYNC_QUIC6 не задано, то берется NFQWS_OPT_DESYNC_QUIC. + +Настройка системы управления выборочным traffic offload (только если поддерживается) +donttouch : выборочное управление отключено, используется системная настройка, простой инсталятор выключает системную настройку, если она не совместима с выбранным режимом +none : выборочное управление отключено, простой инсталятор выключает системную настройку +software : выборочное управление включено в режиме software, простой инсталятор выключает системную настройку +hardware : выборочное управление включено в режиме hardware, простой инсталятор выключает системную настройку + +FLOWOFFLOAD=donttouch + +Параметр GETLIST указывает инсталятору install_easy.sh какой скрипт дергать +для обновления списка заблокированных ip или хостов. +Он же вызывается через get_config.sh из запланированных заданий (crontab или systemd timer). +Поместите сюда название скрипта, который будете использовать для обновления листов. +Если не нужно, то параметр следует закомментировать. + +Можно индивидуально отключить ipv4 или ipv6. Если параметр закомментирован или не равен "1", +использование протокола разрешено. +#DISABLE_IPV4=1 +DISABLE_IPV6=1 + +Количество потоков для многопоточного DNS ресолвера mdig (1..100). +Чем их больше, тем быстрее, но не обидится ли на долбежку ваш DNS сервер ? +MDIG_THREADS=30 + +Место для хранения временных файлов. При скачивании огромных реестров в /tmp места может не хватить. +Если файловая система на нормальном носителе (не встроенная память роутера), то можно +указать место на флэшке или диске. +TMPDIR=/opt/zapret/tmp + +Опции для создания ipset-ов и nfset-ов + +SET_MAXELEM=262144 +IPSET_OPT="hashsize 262144 maxelem 2097152" + +Хук, позволяющий внести ip адреса динамически. $1 = имя таблицы +Адреса выводятся в stdout. В случае nfset автоматически решается проблема возможного пересечения интервалов. +IPSET_HOOK="/etc/zapret.ipset.hook" + +ПРО РУГАНЬ в dmesg по поводу нехватки памяти. +Может так случиться, что памяти в системе достаточно, но при попытке заполнить огромный ipset +ядро начинает громко ругаться, ipset заполняется не полностью. +Вероятная причина в том, что превышается hashsize, заданный при создании ipset (create_ipset.sh). +Происходит переаллокация списка, не находится непрерывных фрагментов памяти нужной длины. +Это лечится увеличением hashsize. Но чем больше hashsize, тем больше занимает ipset в памяти. +Задавать слишком большой hashsize для недостаточно больших списков нецелесообразно. + +Опции для вызова ip2net. Отдельно для листов ipv4 и ipv6. +IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4" +IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5" + +Включить или выключить сжатие больших листов в скриптах ipset/*.sh. По умолчанию включено. +GZIP_LISTS=1 + +Команда для перезагрузки ip таблиц фаервола. +Если не указано или пустое, выбирается автоматически ipset или ipfw при их наличии. +На BSD системах с PF нет автоматической загрузки. Там нужно указать команду явно : pfctl -f /etc/pf.conf +На более новых pfctl (есть в новых FreeBSD, нет в OpenBSD 6.8) можно дать команду загрузки только таблиц : pfctl -Tl -f /etc/pf.conf +"-" означает отключение загрузки листов даже при наличии поддерживаемого backend. +#LISTS_RELOAD="pfctl -f /etc/pf.conf" +#LISTS_RELOAD=- + +В openwrt существует сеть по умолчанию 'lan'. Только трафик с этой сети будет перенаправлен на tpws. +Но возможно задать другие сети или список сетей : +OPENWRT_LAN="lan lan2 lan3" + +Параметр INIT_APPLY_FW=1 разрешает init скрипту самостоятельно применять правила iptables. +При иных значениях или если параметр закомментирован, правила применены не будут. +Это полезно, если у вас есть система управления фаерволом, в настройки которой и следует прикрутить правила. +На openwrt неприменимо при использовании firewall3+iptables. + +Следующие настройки не актуальны для openwrt : + +Если ваша система работает как роутер, то нужно вписать названия внутренних и внешних интерфейсов : +IFACE_LAN=eth0 +IFACE_WAN=eth1 +IFACE_WAN6="henet ipsec0" +Несколько интерфейсов могут быть вписаны через пробел. +Если IFACE_WAN6 не задан, то берется значение IFACE_WAN. + +ВАЖНО : настройка маршрутизации , маскарада и т.д. не входит в задачу zapret. +Включаются только режимы, обеспечивающие перехват транзитного трафика. +Возможно определить несколько интерфейсов следующим образом : IFACE_LAN="eth0 eth1 eth2" + +Прикручивание к системе управления фаерволом или своей системе запуска +---------------------------------------------------------------------- + +Если вы используете какую-то систему управления фаерволом, то она может вступать в конфликт +с имеющимся скриптом запуска. При повторном применении правил она могла бы поломать настройки iptables от zapret. +В этом случае правила для iptables должны быть прикручены к вашему фаерволу отдельно от запуска tpws или nfqws. + +Следующие вызовы позволяют применить или убрать правила iptables отдельно : + + /opt/zapret/init.d/sysv/zapret start_fw + /opt/zapret/init.d/sysv/zapret stop_fw + /opt/zapret/init.d/sysv/zapret restart_fw + +А так можно запустить или остановить демоны отдельно от фаервола : + + /opt/zapret/init.d/sysv/zapret start_daemons + /opt/zapret/init.d/sysv/zapret stop_daemons + /opt/zapret/init.d/sysv/zapret restart_daemons + +nftables сводят практически на нет конфликты между разными системами управления, поскольку позволяют +использовать независимые таблицы и хуки. Используется отдельная nf-таблица "zapret". +Если ваша система ее не будет трогать, скорее всего все будет нормально. + +Для nftables предусмотрено несколько дополнительных вызовов : + +Посмотреть set-ы интерфейсов, относящихся к lan, wan и wan6. По ним идет завертывание трафика. +А так же таблицу flow table с именами интерфейсов ingress hook. + /opt/zapret/init.d/sysv/zapret list_ifsets + +Обновить set-ы интерфейсов, относящихся к lan, wan и wan6. +Для традиционных linux список интерфейсов берется из переменных конфига IFACE_LAN, IFACE_WAN. +Для openwrt определяется автоматически. Множество lanif может быть расширено параметром OPENWRT_LAN. +Все интерфейсы lan и wan так же добавляются в ingress hook от flow table. + /opt/zapret/init.d/sysv/zapret reload_ifsets + +Просмотр таблицы без содержимого set-ов. Вызывает nft -t list table inet zapret + /opt/zapret/init.d/sysv/zapret list_table + +Так же возможно прицепиться своим скриптом к любой стадии применения и снятия фаервола со стороны zapret скриптов : + +INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up" +INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up" +INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down" +INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down" + +Эти настройки доступны в config. +Может быть полезно, если вам нужно использовать nftables set-ы, например ipban/ipban6. +nfset-ы принадлежат только одной таблице, следовательно вам придется писать правила для таблицы zapret, +а значит нужно синхронизироваться с применением/снятием правил со стороны zapret скриптов. + + +Вариант custom +-------------- + +custom код вынесен в отдельный shell include +/opt/zapret/init.d/sysv/custom +или +/opt/zapret/init.d/openwrt/custom + +Нужно свой код вписать в функции : +zapret_custom_daemons +zapret_custom_firewall +zapret_custom_firewall_nft + +В файле custom пишите ваш код, пользуясь хелперами из "functions" или "zapret". +Смотрите как там сделано добавление iptables или запуск демонов. +Используя хелпер функции, вы избавитесь от необходимости учитывать все возможные случаи +типа наличия/отсутствия ipv6, является ли система роутером, имена интерфейсов, ... +Хелперы это учитывают , вам нужно сосредоточиться лишь на фильтрах {ip,nf}tables и +параметрах демонов. + +Код для openwrt и sysv немного отличается. В sysv нужно обрабатывать и запуск, и остановку демонов. +Запуск это или остановка передается в параметре $1 (0 или 1). +В openwrt за остановку отвечает procd. + +Для фаервола кастом пишется отдельно для iptables и nftables. Все очень похоже, но отличается +написание фильтров и названия процедур хелперов. Если вам не нужны iptables или nftables - +можете не писать соответствующую функцию. + +Готовый custom скрипт custom-tpws4http-nfqws4https позволяет применить дурение +tpws к http и nfqws к https. При этом поддерживаются установки из config. +Его можно использовать как стартовую точку для написания своих скриптов. + + +Простая установка +----------------- + +install_easy.sh автоматизирует ручные варианты процедур установки (см manual_setup.txt). +Он поддерживает OpenWRT, linux системы на базе systemd или openrc и MacOS. + +Для более гибкой настройки перед запуском инсталятора следует выполнить раздел "Выбор параметров". + +Если система запуска поддерживается, но используется не поддерживаемый инсталятором менеджер пакетов +или названия пакетов не соответствуют прописанным в инсталятор, пакеты нужно установить вручную. +Всегда требуется curl. ipset - только для режима iptables, для nftables - не нужен. + +Для совсем обрезанных дистрибутивов (alpine) требуется отдельно установить iptables и ip6tables, либо nftables. + +В комплекте идут статические бинарики для большинства архитектур. Какой-то из них подойдет +с вероятностью 99%. Но если у вас экзотическая система, инсталятор попробует собрать бинарики сам +через make. Для этого нужны gcc, make и необходимые -dev пакеты. Можно форсировать режим +компиляции следующим вызовом : + + install_easy.sh make + +Под openwrt все уже сразу готово для использования системы в качестве роутера. +Имена интерфейсов WAN и LAN известны из настроек системы. +Под другими системами роутер вы настраиваете самостоятельно. Инсталятор в это не вмешивается. +Инсталятор в зависимости от выбранного режима может спросить LAN и WAN интерфейсы. +Нужно понимать, что заворот проходящего трафика на tpws в прозрачном режиме происходит до выполнения маршрутизации, +следовательно возможна фильтрация по LAN и невозможна по WAN. +Решение о завороте на tpws локального исходящего трафика принимается после выполнения маршрутизации, +следовательно ситуация обратная : LAN не имеет смысла, фильтрация по WAN возможна. +Заворот на nfqws происходит всегда после маршрутизации, поэтому к нему применима только фильтрация по WAN. +Возможность прохождения трафика в том или ином направлении настраивается вами в процессе конфигурации роутера. + +Деинсталяция выполняется через uninstall_easy.sh + + +Простая установка на openwrt +---------------------------- + +Работает только если у вас на роутере достаточно места. + +Копируем zapret на роутер в /tmp. + +Запускаем установщик : + /tmp/zapret/install_easy.sh +Он скопирует в /opt/zapret только необходимый минимум файлов : + config + install_easy.sh + uninstall_easy.sh + install_bin.sh + init.d/openwrt/* + ipset/* + binaries/<ваша архитектура>/{tpws,nfqws,ip2net,mdig} + +После успешной установки можно удалить zapret из tmp для освобождения RAM : + rm -r /tmp/zapret + +Для более гибкой настройки перед запуском инсталятора следует выполнить раздел "Выбор параметров". + + +Android +------- + +Без рута забудьте про nfqws и tpws в режиме transparent proxy. tpws будет работать только в режиме --socks. + +Ядра Android имеют поддержку NFQUEUE. nfqws работает. + +В стоковых ядрах нет поддержки ipset. В общем случае сложность задачи по поднятию ipset варьируется от +"не просто" до "почти невозможно". Если только вы не найдете готовое собранное ядро под ваш девайс. + +tpws будет работать в любом случае, он не требует чего-либо особенного. +В android нет /etc/passwd, потому опция --user не будет работать. Вместо нее можно +пользоваться числовыми user id и опцией --uid. +Рекомендую использовать gid 3003 (AID_INET). Иначе можете получить permission denied на создание сокета. +Например : --uid 1:3003 +В iptables укажите : "! --uid-owner 1" вместо "! --uid-owner tpws". +Напишите шелл скрипт с iptables и tpws, запускайте его средствами вашего рут менеджера. +Скрипты автозапуска лежат тут : +magisk : /data/adb/service.d +supersu : /system/su.d + +nfqws может иметь такой глюк. При запуске с uid по умолчанию (0x7FFFFFFF) при условии работы на сотовом интерфейсе +и отключенном кабеле внешнего питания система может частично виснуть. Перестает работать тач и кнопки, +но анимация на экране может продолжаться. Если экран был погашен, то включить его кнопкой power невозможно. +Это, видимо, связано с переводом в suspend процессов с определенным UID. UID соответствует приложению или +системному сервису. По UID android определяет политику power saving. +Так же возможно, что глюк связан с кривым драйвером сотового интерфейса от китайцев, поскольку при использовании +wifi такого не наблюдается. suspend обработчика nfqueue на обычном linux не вызывает подобных фатальных последствий. +Изменение UID на низкий (--uid 1 подойдет) позволяет решить эту проблему. +Глюк был замечен на android 8.1 на девайсе , основанном на платформе mediatek. + +Ответ на вопрос куда поместить tpws на android без рута, чтобы потом его запускать из приложений. +Файл заливаем через adb shell в /data/local/tmp/, лучше всего в субфолдер. +mkdir /data/local/tmp/zapret +adb push tpws /data/local/tmp/zapret +chmod 755 /data/local/tmp/zapret /data/local/tmp/zapret/tpws +chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws + +Мобильные модемы и роутеры huawei +--------------------------------- + +Устройства типа E3372, E8372, E5770 разделяют общую идеологию построения системы. +Имеются 2 вычислительных ядра. Одно ядро выполняет vxworks, другое - linux. +На 4pda имеются модицифированные прошивки с telnet и adb. Их и нужно использовать. + +Дальнейшие утверждения проверены на E8372. На других может быть аналогично или похоже. +Присутствуют дополнительные аппаратные блоки для offload-а сетевых функций. +Не весь трафик идет через linux. Исходящий трафик с самого модема проходит +цепочку OUTPUT нормально, на FORWARD =>wan часть пакетов выпадает из tcpdump. + +tpws работает обычным образом. + +nfqueue поломан. можно собрать фиксящий модуль https://github.com/im-0/unfuck-nfqueue-on-e3372h, +используя исходники с huawei open source. Исходники содержат тулчейн и полусобирающееся, +неактуальное ядро. Конфиг можно взять с рабочего модема из /proc/config.gz. +С помощью этих исходников умельцы могут собрать модуль unfuck_nfqueue.ko. +После его применения NFQUEUE и nfqws для arm работают нормально. + +Чтобы избежать проблемы с offload-ом при использвании nfqws, следует комбинировать tpws в режиме tcp proxy и nfqws. +Правила NFQUEUE пишутся для цепочки OUTPUT. +connbytes придется опускать, поскольку модуля в ядре нет. Но это не смертельно. + +Скрипт автозапуска - /system/etc/autorun.sh. Создайте свой скрипт настройки zapret, +запускайте из конца autorun.sh через "&". Скрипт должен в начале делать sleep 5, чтобы дождаться +поднятия сети и iptables от huawei. + +ПРЕДУПРЕЖДЕНИЕ. +На этом модеме происходят хаотические сбросы соединений tcp по непонятным причинам. +Выглядит это так, если запускать curl с самого модема : + curl www.ru + curl: (7) Failed to connect to www.ru port 80: Host is unreachable +Возникает ошибка сокета EHOSTUNREACH (errno -113). То же самое видно в tpws. +В броузере не подгружаются части веб страниц, картинки, стили. +В tcpdump на внешнем интерфейсе eth_x виден только единственный и безответный SYN пакет, без сообщений ICMP. +ОС каким-то образом узнает о невозможности установить TCP соединение и выдает ошибку. +Если выполнять подключение с клиента, то SYN пропадают, соединение не устанавливается. +ОС клиента проводит ретрансмиссию, и с какого-то раза подключение удается. +Поэтому без tcp проксирования в этой ситуации сайты тупят, но загружаются, а с проксированием +подключение выполняется, но вскоре сбрасывается без каких-либо данных, и броузеры не пытаются установить +его заново. Поэтому качество броузинга с tpws может быть хуже, но дело не в tpws. +Частота сбросов заметно возрастает, если запущен торент клиент, имеется много tcp соединений. +Однако, причина не в переполнении таблицы conntrack. Увеличение лимитов и очистка conntrack не помогают. +Предположительно эта особенность связана с обработкой пакетов сброса соединения в hardware offload. +Точного ответа на вопрос у меня нет. Если вы знаете - поделитесь, пожалуйста. +Чтобы не ухудшать качество броузинга, можно фильтровать заворот на tpws по ip фильтру. +Поддержка ipset отсутствует. Значит, все, что можно сделать - создать индивидуальные правила +на небольшое количество хостов. + +Некоторые наброски скриптов присутствуют в files/huawei. Не готовое решение ! Смотрите, изучайте, приспосабливайте. +Здесь можно скачать готовые полезные статические бинарики для arm, включая curl : https://github.com/bol-van/bins + + +FreeBSD, OpenBSD, MacOS +----------------------- + +Описано в docs/bsd.txt + + +Windows (WSL) +------------- + +tpws в режиме socks можно запускать и под более-менее современными билдами windows 10 и windows server +с установленным WSL. Совсем не обязательно устанавливать дистрибутив убунту, как вам напишут почти в каждой +статье про WSL, которую вы найдете в сети. tpws - статический бинарик, ему дистрибутив не нужен. + +Установить WSL : dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all +Скопировать на целевую систему binaries/x86_64/tpws_wsl.tgz. +Выполнить : wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz +Запустить : wsl --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 <параметры_дурения> +Прописать socks 127.0.0.1:1080 в броузер или другую программу. + +Удаление : wsl --unregister tpws + +Проверено на windows 10 build 19041 (20.04). + +ЗАМЕЧАНИЕ. Под Windows существует нативное решение GoodByeDPI, выполняющее дурение на пакетном уровне (по типу nfqws). + + +Другие прошивки +--------------- + +Для статических бинариков не имеет значения на чем они запущены : PC, android, приставка, роутер, любой другой девайс. +Подойдет любая прошивка, дистрибутив linux. Статические бинарики запустятся на всем. +Им нужно только ядро с необходимыми опциями сборки или модулями. +Но кроме бинариков в проекте используются еще и скрипты, в которых задействуются некоторые +стандартные программы. + +Основные причины почему нельзя просто так взять и установить эту систему на что угодно : + * отсутствие доступа к девайсу через shell + * отсутствие рута + * отсутствие раздела r/w для записи и энергонезависимого хранения файлов + * отсутствие возможности поставить что-то в автозапуск + * отсутствие cron + * неотключаемый flow offload или другая проприетарщина в netfilter + * недостаток модулей ядра или опций его сборки + * недостаток модулей iptables (/usr/lib/iptables/lib*.so) + * недостаток стандартных программ (типа ipset, curl) или их кастрированность (облегченная замена) + * кастрированный или нестандартный шелл sh + +Если в вашей прошивке есть все необходимое, то вы можете адаптировать zapret под ваш девайс в той или иной степени. +Может быть у вас не получится поднять все части системы, однако вы можете хотя бы попытаться +поднять tpws и завернуть на него через -j REDIRECT весь трафик на порт 80. +Если вам есть куда записать tpws, есть возможность выполнять команды при старте, то как минимум +это вы сделать сможете. Скорее всего поддержка REDIRECT в ядре есть. Она точно есть на любом роутере, +на других устройствах под вопросом. NFQUEUE, ipset на большинстве прошивок отсутствуют из-за ненужности. + +Пересобрать ядро или модули для него будет скорее всего достаточно трудно. +Для этого вам необходимо будет по крайней мере получить исходники вашей прошивки. +User mode компоненты могут быть привнесены относительно безболезненно, если есть место куда их записать. +Специально для девайсов, имеющих область r/w, существует проект entware. +Некоторые прошивки даже имеют возможность его облегченной установки через веб интерфейс. +entware содержит репозиторий user-mode компонент, которые устанавливаются в /opt. +С их помощью можно компенсировать недостаток ПО основной прошивки, за исключением ядра. + +Можно попытаться использовать sysv init script таким образом, как это описано в разделе +"Прикручивание к системе управления фаерволом или своей системе запуска". +В случае ругани на отсутствие каких-то базовых программ, их следует восполнить посредством entware. +Перед запуском скрипта путь к дополнительным программам должен быть помещен в PATH. + +Подробное описание настроек для других прошивок выходит за рамки данного проекта. + +Openwrt является одной из немногих относительно полноценных linux систем для embedded devices. +Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивки : + * полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть + * корень r/w. это практически уникальная особенность openwrt. заводские и большинство альтернативных прошивок + построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области + встроенной памяти, называемой nvram. не имеющие r/w корня системы сильно кастрированы. они не имеют + возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном + на чуть более продвинутого, чем обычно, пользователя и управление имеющимся функционалом через веб интерфейс, + но функционал фиксированно ограничен. альтернативные прошивки как правило могут монтировать r/w раздел + в какую-то область файловой системы, заводские обычно могут монтировать лишь флэшки, подключенные к USB, + и не факт, что есть поддержка unix файловых системы. может быть поддержка только fat и ntfs. + * возможность выноса корневой файловой системы на внешний носитель (extroot) или создания на нем оверлея (overlay) + * наличие менеджера пакетов opkg и репозитория софта + * flow offload предсказуемо, стандартно и выборочно управляем, а так же отключаем + * в репозитории есть все модули ядра, их можно доустановить через opkg. ядро пересобирать не нужно. + * в репозитории есть все модули iptables, их можно доустановить через opkg + * в репозитории есть огромное количество стандартных программ и дополнительного софта + * наличие SDK, позволяющего собрать недостающее + + +Обход блокировки через сторонний хост +------------------------------------- + +Если не работает автономный обход, приходится перенаправлять трафик через сторонний хост. +Предлагается использовать прозрачный редирект через socks5 посредством iptables+redsocks, либо iptables+iproute+vpn. +Настройка варианта с redsocks на openwrt описана в redsocks.txt. +Настройка варианта с iproute+wireguard - в wireguard_iproute_openwrt.txt. + + +Почему стоит вложиться в покупку VPS +------------------------------------ + +VPS - это виртуальный сервер. Существует огромное множество датацентров, предлагающих данную услугу. +На VPS могут выполняться какие угодно задачи. От простого веб сайта до навороченной системы собственной разработки. +Можно использовать VPS и для поднятия собственного vpn или прокси. +Сама широта возможных способов применения , распространенность услуги сводят к минимуму возможности +регуляторов по бану сервисов такого типа. Да, если введут белые списки, то решение загнется, но это будет уже другая +реальность, в которой придется изобретать иные решения. +Пока этого не сделали, никто не будет банить хостинги просто потому , что они предоставляют хостинг услуги. +Вы как индивидуум скорее всего никому не нужны. Подумайте чем вы отличаетесь от известного VPN провайдера. +VPN провайдер предоставляет _простую_ и _доступную_ услугу по обходу блокировок для масс. +Этот факт делает его первоочередной целью блокировки. РКН направит уведомление, после отказа сотрудничать +заблокирует VPN. Предоплаченная сумма пропадет. +У регуляторов нет и никогда не будет ресурсов для тотальной проверки каждого сервера в сети. +Возможен китайский расклад, при котором DPI выявляет vpn протоколы и динамически банит IP серверов, +предоставляющих нелицензированный VPN. Но имея знания, голову, вы всегда можете обфусцировать +vpn трафик или применить другие типы VPN, более устойчивые к анализу на DPI или просто менее широкоизвестные, +а следовательно с меньшей вероятностью обнаруживамые регулятором. +У вас есть свобода делать на вашем VPS все что вы захотите, адаптируясь к новым условиям. +Да, это потребует знаний. Вам выбирать учиться и держать ситуацию под контролем, когда вам ничего запретить +не могут, или покориться системе. + +VPS можно прибрести в множестве мест. Существуют специализированные на поиске предложений VPS порталы. +Например, вот этот : https://vps.today/ +Для персонального VPN сервера обычно достаточно самой минимальной конфигурации, но с безлимитным трафиком или +с большим лимитом по трафику (терабайты). Важен и тип VPS. Openvz подойдет для openvpn, но +вы не поднимете на нем wireguard, ipsec, то есть все, что требует kernel mode. +Для kernel mode требуется тип виртуализации, предполагающий запуск полноценного экземпляра ОС linux +вместе с ядром. Подойдут kvm, xen, hyper-v, vmware. + +По цене можно найти предложения, которые будут дешевле готовой VPN услуги, но при этом вы сам хозяин в своей лавке +и не рискуете попасть под бан регулятора, разве что "заодно" под ковровую бомбардировку с баном миллионов IP. +Кроме того, если вам совсем все кажется сложным, прочитанное вызывает ступор, и вы точно знаете, что ничего +из описанного сделать не сможете, то вы сможете хотя бы использовать динамическое перенаправление портов ssh +для получения шифрованного socks proxy и прописать его в броузер. Знания linux не нужны совсем. +Это вариант наименее напряжный для чайников, хотя и не самый удобный в использовании. diff --git a/docs/redsocks.txt b/docs/redsocks.txt index 6709867..f0c9983 100644 --- a/docs/redsocks.txt +++ b/docs/redsocks.txt @@ -1,4 +1,4 @@ -Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему. +Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему. Если вы не знаете основ сетей, linux, openwrt, а пытаетесь что-то скопипастить отсюда без малейшего понимания смысла, то маловероятно, что у вас что-то заработает. Не тратье свое время напрасно. Цель - донести принципы как это настраивается вообще, а не указать какую буковку где вписать. diff --git a/tpws/helpers.h b/tpws/helpers.h index 9524bc5..1a31765 100644 --- a/tpws/helpers.h +++ b/tpws/helpers.h @@ -31,6 +31,11 @@ bool set_hl(int fd, int hl); bool set_ttl_hl(int fd, int ttl); int get_so_error(int fd); +// alignment-safe functions static inline uint16_t pntoh16(const uint8_t *p) { return ((uint16_t)p[0] << 8) | (uint16_t)p[1]; } +static inline void phton16(uint8_t *p, uint16_t v) { + p[0] = (uint8_t)(v>>8); + p[1] = (uint8_t)v; +} diff --git a/tpws/params.h b/tpws/params.h index ec1925c..e646840 100644 --- a/tpws/params.h +++ b/tpws/params.h @@ -8,6 +8,7 @@ #include "strpool.h" enum splithttpreq { split_none = 0, split_method, split_host }; +enum tlsrec { tlsrec_none = 0, tlsrec_sni, tlsrec_pos }; enum bindll { unwanted=0, no, prefer, force }; #define MAX_BINDS 32 @@ -41,6 +42,8 @@ struct params_s int hostpad; char hostspell[4]; enum splithttpreq split_http_req; + enum tlsrec tlsrec; + int tlsrec_pos; bool split_any_protocol; int split_pos; bool disorder; diff --git a/tpws/tamper.c b/tpws/tamper.c index 9c22666..387a088 100644 --- a/tpws/tamper.c +++ b/tpws/tamper.c @@ -4,11 +4,12 @@ #include "params.h" #include "hostlist.h" #include "protocol.h" +#include "helpers.h" #include #include // pHost points to "Host: ..." -bool find_host(char **pHost,char *buf,size_t bs) +bool find_host(uint8_t **pHost,uint8_t *buf,size_t bs) { if (!*pHost) { @@ -23,14 +24,15 @@ bool find_host(char **pHost,char *buf,size_t bs) } static const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL }; -void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos) +// segment buffer has at least 5 extra bytes to extend data block +void modify_tcp_segment(uint8_t *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos) { - char *p, *pp, *pHost = NULL; + uint8_t *p, *pp, *pHost = NULL; size_t method_len = 0, pos; const char **method; bool bIsHttp = false, bBypass = false; char bRemovedHostSpace = 0; - char Host[128]; + char *pc, Host[128]; *split_pos=0; @@ -57,7 +59,7 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si memcpy(Host, p, pp - p); Host[pp - p] = '\0'; VPRINT("Requested Host is : %s", Host) - for(p = Host; *p; p++) *p=tolower(*p); + for(pc = Host; *pc; pc++) *pc=tolower(*pc); bBypass = !HostlistCheck(params.hostlist, params.hostlist_exclude, Host); } if (!bBypass) @@ -208,28 +210,62 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si { VPRINT("Not acting on this request") } + return; } - else if (params.split_pos && params.split_pos < *size) + + if (IsTLSClientHello(segment,*size)) { - // split-pos is the only parameter applicable to non-http block (may be https ?) - if (IsTLSClientHello((uint8_t*)segment,*size)) - { - char host[256]; + char host[256]; + size_t tpos=0,elen; + const uint8_t *ext; - VPRINT("packet contains TLS ClientHello") - // we need host only if hostlist is present - if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,host,sizeof(host))) + VPRINT("packet contains TLS ClientHello") + // we need host only if hostlist is present + if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,host,sizeof(host))) + { + VPRINT("hostname: %s",host) + if (!HostlistCheck(params.hostlist, params.hostlist_exclude, host)) { - VPRINT("hostname: %s",host) - if (!HostlistCheck(params.hostlist, params.hostlist_exclude, host)) - { - VPRINT("Not acting on this request") - return; - } + VPRINT("Not acting on this request") + return; } - *split_pos = params.split_pos; } - else if (params.split_any_protocol) + switch(params.tlsrec) + { + case tlsrec_sni: + if (TLSFindExt(segment,*size,0,&ext,&elen)) + tpos = ext-segment+1; // between typical 1st and 2nd char of hostname + break; + case tlsrec_pos: + tpos = params.tlsrec_pos; + break; + default: + break; + } + if (tpos) + { + // construct 2 TLS records from one + uint16_t l = pntoh16(segment+3); // length + if (l>=2) + { + // length is checked in IsTLSClientHello and cannot exceed buffer size + if (tpos>=l) tpos=1; + VPRINT("making 2 TLS records at pos %zu",tpos) + memmove(segment+5+tpos+5,segment+5+tpos,l-tpos); + segment[5+tpos] = segment[0]; + segment[5+tpos+1] = segment[1]; + segment[5+tpos+2] = segment[2]; + phton16(segment+5+tpos+3,l-tpos); + phton16(segment+3,tpos); + *size += 5; + } + } + + if (params.split_pos < *size) *split_pos = params.split_pos; + return; } + + if (params.split_any_protocol && params.split_pos < *size) + *split_pos = params.split_pos; } diff --git a/tpws/tamper.h b/tpws/tamper.h index 6cc49bc..0c70f88 100644 --- a/tpws/tamper.h +++ b/tpws/tamper.h @@ -1,7 +1,8 @@ #pragma once #include +#include #include -bool find_host(char **pHost,char *buf,size_t bs); -void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos); +bool find_host(uint8_t **pHost,uint8_t *buf,size_t bs); +void modify_tcp_segment(uint8_t *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos); diff --git a/tpws/tpws.c b/tpws/tpws.c index 2c399a3..7d6e813 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -174,6 +174,8 @@ static void exithelp() " --methodspace\t\t\t; add extra space after method\n" " --methodeol\t\t\t; add end-of-line before method\n" " --unixeol\t\t\t; replace 0D0A to 0A\n" + " --tlsrec=sni\t\t\t; make 2 TLS records. split at SNI. don't split if SNI is not present\n" + " --tlsrec-pos=\t\t; make 2 TLS records. split at specified pos\n" ); exit(1); } @@ -288,19 +290,21 @@ void parse_params(int argc, char *argv[]) { "methodeol",no_argument,0,0 },// optidx=28 { "hosttab",no_argument,0,0 },// optidx=29 { "unixeol",no_argument,0,0 },// optidx=30 - { "hostlist",required_argument,0,0 },// optidx=31 - { "hostlist-exclude",required_argument,0,0 },// optidx=32 - { "pidfile",required_argument,0,0 },// optidx=33 - { "debug",optional_argument,0,0 },// optidx=34 - { "local-rcvbuf",required_argument,0,0 },// optidx=35 - { "local-sndbuf",required_argument,0,0 },// optidx=36 - { "remote-rcvbuf",required_argument,0,0 },// optidx=37 - { "remote-sndbuf",required_argument,0,0 },// optidx=38 - { "socks",no_argument,0,0 },// optidx=39 - { "no-resolve",no_argument,0,0 },// optidx=40 - { "skip-nodelay",no_argument,0,0 },// optidx=41 + { "tlsrec",required_argument,0,0 },// optidx=31 + { "tlsrec-pos",required_argument,0,0 },// optidx=32 + { "hostlist",required_argument,0,0 },// optidx=33 + { "hostlist-exclude",required_argument,0,0 },// optidx=34 + { "pidfile",required_argument,0,0 },// optidx=35 + { "debug",optional_argument,0,0 },// optidx=36 + { "local-rcvbuf",required_argument,0,0 },// optidx=37 + { "local-sndbuf",required_argument,0,0 },// optidx=38 + { "remote-rcvbuf",required_argument,0,0 },// optidx=39 + { "remote-sndbuf",required_argument,0,0 },// optidx=40 + { "socks",no_argument,0,0 },// optidx=41 + { "no-resolve",no_argument,0,0 },// optidx=42 + { "skip-nodelay",no_argument,0,0 },// optidx=43 #if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__) - { "enable-pf",no_argument,0,0 },// optidx=42 + { "enable-pf",no_argument,0,0 },// optidx=44 #endif { NULL,0,NULL,0 } }; @@ -472,7 +476,7 @@ void parse_params(int argc, char *argv[]) break; case 24: /* split-pos */ i = atoi(optarg); - if (i) + if (i>0) params.split_pos = i; else { @@ -504,7 +508,27 @@ void parse_params(int argc, char *argv[]) params.unixeol = true; params.tamper = true; break; - case 31: /* hostlist */ + case 31: /* tlsrec */ + if (!strcmp(optarg, "sni")) + params.tlsrec = tlsrec_sni; + else + { + fprintf(stderr, "Invalid argument for tlsrec\n"); + exit_clean(1); + } + params.tamper = true; + break; + case 32: /* tlsrec-pos */ + if ((params.tlsrec_pos = atoi(optarg))>0) + params.tlsrec = tlsrec_pos; + else + { + fprintf(stderr, "Invalid argument for tlsrec-pos\n"); + exit_clean(1); + } + params.tamper = true; + break; + case 33: /* hostlist */ if (!strlist_add(¶ms.hostlist_files, optarg)) { fprintf(stderr, "strlist_add failed\n"); @@ -512,7 +536,7 @@ void parse_params(int argc, char *argv[]) } params.tamper = true; break; - case 32: /* hostlist-exclude */ + case 34: /* hostlist-exclude */ if (!strlist_add(¶ms.hostlist_exclude_files, optarg)) { fprintf(stderr, "strlist_add failed\n"); @@ -520,36 +544,36 @@ void parse_params(int argc, char *argv[]) } params.tamper = true; break; - case 33: /* pidfile */ + case 35: /* pidfile */ strncpy(params.pidfile,optarg,sizeof(params.pidfile)); params.pidfile[sizeof(params.pidfile)-1]='\0'; break; - case 34: + case 36: params.debug = optarg ? atoi(optarg) : 1; break; - case 35: /* local-rcvbuf */ + case 37: /* local-rcvbuf */ params.local_rcvbuf = atoi(optarg)/2; break; - case 36: /* local-sndbuf */ + case 38: /* local-sndbuf */ params.local_sndbuf = atoi(optarg)/2; break; - case 37: /* remote-rcvbuf */ + case 39: /* remote-rcvbuf */ params.remote_rcvbuf = atoi(optarg)/2; break; - case 38: /* remote-sndbuf */ + case 40: /* remote-sndbuf */ params.remote_sndbuf = atoi(optarg)/2; break; - case 39: /* socks */ + case 41: /* socks */ params.proxy_type = CONN_TYPE_SOCKS; break; - case 40: /* no-resolve */ + case 42: /* no-resolve */ params.no_resolve = true; break; - case 41: /* skip-nodelay */ + case 43: /* skip-nodelay */ params.skip_nodelay = true; break; #if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__) - case 42: /* enable-pf */ + case 44: /* enable-pf */ params.pf_enable = true; break; #endif diff --git a/tpws/tpws_conn.c b/tpws/tpws_conn.c index 51df4dd..d42abc7 100644 --- a/tpws/tpws_conn.c +++ b/tpws/tpws_conn.c @@ -133,7 +133,7 @@ ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl) } -static bool send_buffer_create(send_buffer_t *sb, char *data, size_t len, int ttl) +static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len, int ttl) { if (sb->data) { @@ -258,7 +258,7 @@ static bool conn_has_unsent_pair(tproxy_conn_t *conn) } -static ssize_t send_or_buffer(send_buffer_t *sb, int fd, char *buf, size_t len, int ttl) +static ssize_t send_or_buffer(send_buffer_t *sb, int fd, const void *buf, size_t len, int ttl) { ssize_t wr=0; if (len) @@ -919,7 +919,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32 if (!conn_partner_alive(conn)) { // throw it to a black hole - char waste[65070]; + uint8_t waste[65070]; ssize_t trd=0; while((rd=recv(conn->fd, waste, sizeof(waste), MSG_DONTWAIT))>0 && trdfd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT); DBGPRINT("recv fd=%d rd=%zd err=%d",conn->fd, rd,errno)