Truncated history

This commit is contained in:
bol-van
2024-10-28 09:32:24 +03:00
commit 2aaa2f7cf3
300 changed files with 43184 additions and 0 deletions

21
docs/LICENSE.txt Normal file
View File

@@ -0,0 +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.

611
docs/bsd.eng.md Normal file
View File

@@ -0,0 +1,611 @@
## Table of contents
- [Table of contents](#table-of-contents)
- [Supported versions](#supported-versions)
- [BSD features](#bsd-features)
- [FreeBSD](#freebsd)
- [`dvtws` quick start](#dvtws-quick-start)
- [PF in FreeBSD](#pf-in-freebsd)
- [`pfsense`](#pfsense)
- [OpenBSD](#openbsd)
- [MacOS](#macos)
- [MacOS easy install](#macos-easy-install)
## Supported versions
FreeBSD 11.x+ , OpenBSD 6.x+, partially MacOS Sierra+
Older versions may work or not.
## BSD features
BSD does not have NFQUEUE. Similar mechanism - divert sockets. In BSD compiling
the source from nfq directory result in `dvtws` binary instead of `nfqws`.
`dvtws` shares most of the code with `nfqws` and offers almost identical
parameters.
FreeBSD has 3 firewalls: IPFilter, ipfw and Packet Filter (PF). OpenBSD has
only PF.
To compile sources:
- FreeBSD: `make`
- OpenBSD: `make bsd`
- MacOS: `make mac`
Compile all programs:
```
make -C /opt/zapret
```
Divert sockets are internal type sockets in the BSD kernel. They have no
relation to network addresses or network packet exchange. They are identified
by a port number `1..65535`. Its like queue number in NFQUEUE. Traffic can be
diverted to a divert socket using firewall rule. If nobody listens on the
specified divert port packets are dropped. Its similar to NFQUEUE without
`--queue-bypass`.
`ipset/*.sh` scripts work with ipfw lookup tables if ipfw is present.
ipfw table is analog to linux `ipset`. Unlike ipsets ipfw tables share v4 an v6
addresses and subnets.
- If ipfw is absent scripts check LISTS_RELOAD config variable.
- If its present then scripts execute a command from LISTS_RELOAD.
- If LISTS_RELOAD=- scripts do not load tables even if ipfw exists.
PF can load ip tables from a file. To use this feature with `ipset/*.sh` scripts disable gzip file creation
using `GZIP_LISTS=0` directive in the `/opt/zapret/config` file.
BSD kernel doesn't implement splice syscall. tpws uses regular recv/send
operations with data copying to user space. Its slower but not critical.
`tpws` uses nonblocking sockets with linux specific epoll feature. In BSD systems
epoll is emulated by epoll-shim library on top of kqueue.
`dvtws` uses some programming HACKs, assumptions and knowledge of discovered
bugs and limitations. BSD systems have many limitations, version specific
features and bugs in low level networking, especially for ipv6. Many years have
passed but BSD code still has 15-20 year artificial limiters in the code. `dvtws`
uses additinal divert socket(s) for layer 3 packet injection if raw sockets do
not allow it. It works for the moment but who knows. Such a usage is not very
documented.
`mdig` and `ip2net` are fully compatible with BSD.
## FreeBSD
Divert sockets require special kernel module `ipdivert`.
Write the following to config files:
`/boot/loader.conf` (create if absent):
```
ipdivert_load="YES"
net.inet.ip.fw.default_to_accept=1
```
`/etc/rc.conf`:
```
firewall_enable="YES"
firewall_script="/etc/rc.firewall.my"
```
`/etc/rc.firewall.my`:
```
ipfw -q -f flush
```
Later you will add ipfw commands to `/etc/rc.firewall.my` to be reapplied after reboot.
You can also run zapret daemons from there. Start them with `--daemon` options, for example
```
pkill ^dvtws$
/opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2
```
To restart firewall and daemons run : `/etc/rc.d/ipfw restart`
Assume `LAN="em1"`, `WAN="em0"`.
`tpws` transparent mode quick start.
For all traffic:
```
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
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
```
Process only table zapret with the exception of table nozapret:
```
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
```
Tables zapret, nozapret, ipban are created by `ipset/*.sh` scripts the same way as in Linux.
Its a good idea to update tables periodically:
```
crontab -e
```
Write the line:
```
0 12 */2 * * /opt/zapret/ipset/get_config.sh
```
When using `ipfw`, `tpws` does not require special permissions for transparent
mode. However without root its not possible to bind to ports less than 1024 and
change UID/GID. Without changing UID tpws will run into recursive loop, and
that's why its necessary to write ipfw rules with the right UID. Redirecting to
ports greater than or equal to 1024 is dangerous. If tpws is not running any
unprivileged process can listen to that port and intercept traffic.
### `dvtws` quick start
For all traffic:
```
ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0
# required for autottl mode only
ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
```
Process only table zapret with the exception of table nozapret:
```
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
# required for autottl mode only
ipfw add 100 divert 989 tcp from table\(zapret\) 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
```
Reinjection 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'. ipv4 frames are filtered using 'sockarg'.
### PF in FreeBSD
The setup is similar to OpenBSD, but there are important nuances.
1. PF support is disabled by default in FreeBSD. Use parameter `--enable-pf`.
2. It's not possible to redirect to `::1`. Need to redirect to the link-local
address of the incoming interface. Look for fe80:... address in ifconfig and
use it for redirection target.
3. pf.conf syntax is a bit different from OpenBSD.
4. How to set maximum table size : sysctl net.pf.request_maxcount=2000000
5. `divert-to` is broken. Loop avoidance scheme does not work.
This makes `dvtws` unusable with pf.
Someone posted kernel patch but 14-RELEASE is still broken.
`/etc/pf.conf`:
```
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::31c:29ff:dee2:1c4d port 988
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988
```
Then:
```
/opt/zapret/tpws/tpws --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force
```
Its not clear how to do rdr-to outgoing traffic. I could not make route-to
scheme work.
### `pfsense`
`pfsense` is based on FreeBSD. Binaries from `binaries/freebsd-x64` are
compiled in FreeBSD 11 and should work. Use `install_bin.sh`. pfsense uses pf
firewall which does not support divert. Fortunately ipfw and ipdivert modules
are present and can be kldload-ed. In older versions it's also necessary to
change firewall order using sysctl commands. In newer versions those sysctl
parameters are absent but the system behaves as required without them.
Sometimes pf may limit `dvtws` abilities. It scrubs ip fragments disabling `dvtws`
ipfrag2 desync mode.
There's autostart script example in `init.d/pfsense`. It should be placed to
`/usr/local/etc/rc.d` and edited. Write your ipfw rules and daemon start
commands. Because git is absent the most convinient way to copy files is ssh.
curl is present by default.
Copy zip with zapret files to `/opt` and unpack there as it's done in other
systems. In this case run `dvtws` as `/opt/zapret/nfq/dvtws`. Or just copy
`dvtws` to `/usr/local/sbin`. As you wish. `ipset` scripts are working, cron is
present. It's possible to renew lists.
If you dont like poverty of default repos its possible to enable FreeBSD repo.
Change `no` to `yes` in `/usr/local/etc/pkg/repos/FreeBSD.conf` and `/usr/local/etc/pkg/repos/pfSense.conf`.
Then it becomes possible to install all the required software including git to download
zapret from github directly.
`/usr/local/etc/rc.d/zapret.sh` (chmod 755)
```
#!/bin/sh
kldload ipfw
kldload ipdivert
# for older pfsense versions. newer do not have these sysctls
sysctl net.inet.ip.pfil.outbound=ipfw,pf
sysctl net.inet.ip.pfil.inbound=ipfw,pf
sysctl net.inet6.ip6.pfil.outbound=ipfw,pf
sysctl net.inet6.ip6.pfil.inbound=ipfw,pf
ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0
pkill ^dvtws$
dvtws --daemon --port 989 --dpi-desync=split2
# required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state
pfctl -d ; pfctl -e
```
I could not make tpws work from ipfw. Looks like there's some conflict between
two firewalls. Only PF redirection works. PF does not allow to freely add and
delete rules. Only anchors can be reloaded. To make an anchor work it must be
referred from the main ruleset. But its managed by pfsense scripts.
One possible solution would be to modify `/etc/inc/filter.inc` as follows:
```
.................
/* MOD */
$natrules .= "# ZAPRET redirection\n";
$natrules .= "rdr-anchor \"zapret\"\n";
$natrules .= "# TFTP proxy\n";
$natrules .= "rdr-anchor \"tftp-proxy/*\"\n";
.................
```
Write the anchor code to `/etc/zapret.anchor`:
```
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::20c:29ff:5ae3:4821 port 988
```
Replace `fe80::20c:29ff:5ae3:4821` with your link local address of the LAN
interface or remove the line if ipv6 is not needed.
Autostart `/usr/local/etc/rc.d/zapret.sh`:
```
pfctl -a zapret -f /etc/zapret.anchor
pkill ^tpws$
tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-http-req=method --split-pos=2
```
After reboot check that anchor is created and referred from the main ruleset:
```
[root@pfSense /]# pfctl -s nat
no nat proto carp all
nat-anchor "natearly/*" all
nat-anchor "natrules/*" all
...................
no rdr proto carp all
rdr-anchor "zapret" all
rdr-anchor "tftp-proxy/*" all
rdr-anchor "miniupnpd" all
[root@pfSense /]# pfctl -s nat -a zapret
rdr pass on em1 inet proto tcp from any to any port = http -> 127.0.0.1 port 988
rdr pass on em1 inet proto tcp from any to any port = https -> 127.0.0.1 port 988
rdr pass on em1 inet6 proto tcp from any to any port = http -> fe80::20c:29ff:5ae3:4821 port 988
rdr pass on em1 inet6 proto tcp from any to any port = https -> fe80::20c:29ff:5ae3:4821 port 988
```
Also there's a way to add redirect in the pfsense UI and start `tpws` from cron using `@reboot` prefix.
This way avoids modification of pfsense code.
## OpenBSD
In OpenBSD default `tpws` bind is ipv6 only. To bind to ipv4 specify
`--bind-addr=0.0.0.0`.
Use `--bind-addr=0.0.0.0 --bind-addr=::` to achieve the same default bind as in
others OSes.
`tpws` for forwarded traffic only :
`/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
```
Then:
```
pfctl -f /etc/pf.conf
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
```
Its not clear how to do rdr-to outgoing traffic. I could not make route-to
scheme work. rdr-to support is done using /dev/pf, that's why transparent mode
requires root.
`dvtws` for all traffic:
`/etc/pf.conf`:
```
pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state
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
```
Then:
```
pfctl -f /etc/pf.conf
./dvtws --port=989 --dpi-desync=split2
```
`dwtws` only for table zapret with the exception of table nozapret :
`/etc/pf.conf`:
```
set limit table-entries 2000000
table <zapret> file "/opt/zapret/ipset/zapret-ip.txt"
table <zapret-user> file "/opt/zapret/ipset/zapret-ip-user.txt"
table <nozapret> file "/opt/zapret/ipset/zapret-ip-exclude.txt"
pass out quick on em0 inet proto tcp to <nozapret> port {80,443}
pass in quick on em0 inet proto tcp from <zapret> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret> port {80,443} no state
pass out quick on em0 inet proto tcp to <zapret> port {80,443} divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} no state
pass out quick on em0 inet proto tcp to <zapret-user> port {80,443} divert-packet port 989 no state
table <zapret6> file "/opt/zapret/ipset/zapret-ip6.txt"
table <zapret6-user> file "/opt/zapret/ipset/zapret-ip-user6.txt"
table <nozapret6> file "/opt/zapret/ipset/zapret-ip-exclude6.txt"
pass out quick on em0 inet6 proto tcp to <nozapret6> port {80,443}
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} no state
pass out quick on em0 inet6 proto tcp to <zapret6> port {80,443} divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} no state
pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-packet port 989 no state
```
Then:
```
pfctl -f /etc/pf.conf
./dvtws --port=989 --dpi-desync=split2
```
divert-packet automatically adds the reverse rule. By default also incoming
traffic will be passwed to `dvtws`. This is highly undesired because it is waste
of cpu resources and speed limiter. The trick with "no state" and "in" rules
allows to bypass auto reverse rule.
`dvtws` in OpenBSD sends all fakes through a divert socket because raw sockets
have critical artificial limitations. Looks like pf automatically prevent
reinsertion of diverted frames. Loop problem does not exist.
OpenBSD forcibly recomputes tcp checksum after divert. Thats why most likely
dpi-desync-fooling=badsum will not work. `dvtws` will warn if you specify this
parameter.
`ipset` scripts do not reload PF by default. To enable reload specify command in
`/opt/zapret/config`:
```
LISTS_RELOAD="pfctl -f /etc/pf.conf"
```
Newer `pfctl` versions can reload tables only:
```
pfctl -Tl -f /etc/pf.conf
```
But OpenBSD 6.8 `pfctl` is old enough and does not support that. Newer FreeBSD do.
Don't forget to disable gzip compression:
```
GZIP_LISTS=0
```
If some list files do not exist and have references in pf.conf it leads to
error. You need to exclude those tables from pf.conf and referencing them
rules. After configuration is done you can put `ipset` script:
```
crontab -e
```
Then write the line:
```
0 12 */2 * * /opt/zapret/ipset/get_config.sh
```
## MacOS
Initially, the kernel of this OS was based on BSD. That's why it is still BSD
but a lot was modified by Apple. As usual a mass commercial project priorities
differ from their free counterparts. Apple guys do what they want.
MacOS used to have ipfw but it was removed later and replaced by PF. It looks
like divert sockets are internally replaced with raw. Its possible to request a
divert socket but it behaves exactly as raw socket with all its BSD inherited +
apple specific bugs and feature. The fact is that divert-packet in
`/etc/pf.conf` does not work. pfctl binary does not contain the word `divert`.
`dvtws` does compile but is useless.
After some efforts `tpws` works. Apple has removed some important stuff from
their newer SDKs (DIOCNATLOOK) making them undocumented and unsupported.
With important definitions copied from an older SDK it was possible to make
transparent mode working again. But this is not guaranteed to work in the
future versions.
Another MacOS unique feature is root requirement while polling `/dev/pf`.
By default tpws drops root. Its necessary to specify `--user=root` to stay with
root.
In other aspects PF behaves very similar to FreeBSD and shares the same pf.conf
syntax.
In MacOS redirection works both for passthrough and outgoing traffic. Outgoing
redirection requires route-to rule. Because tpws is forced to run as root to
avoid loop its necessary to exempt root from the redirection. That's why DPI
bypass will not work for local requests from root.
If you do ipv6 routing you have to get rid of "secured" ipv6 address
assignment.
"secured" addresses are designed to be permanent and not related to the MAC
address.
And they really are. Except for link-locals.
If you just reboot the system link-locals will not change. But next day they
will change.
Not necessary to wait so long. Just change the system time to tomorrow and reboot.
Link-locals will change (at least they change in vmware guest). Looks like its a kernel bug.
Link locals should not change. Its useless and can be harmful. Cant use LL as a gateway.
The easiest solution is to disable "secured" addresses.
Outgoing connections prefer randomly generated temporary addressesas like in other systems.
Put the string `net.inet6.send.opmode=0` to `/etc/sysctl.conf`. If not present
- create it.
Then reboot the system.
If you dont like this solution you can assign an additional static ipv6 address
from `fc00::/7` range with `/128` prefix to your LAN interface and use it as
the gateway address.
`tpws` transparent mode only for outgoing connections.
`/etc/pf.conf`:
```
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root }
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root }
```
Then:
```
pfctl -ef /etc/pf.conf
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force
```
`tpws` transparent mode for both passthrough and outgoing connections. en1 - LAN.
```
ifconfig en1 | grep fe80
inet6 fe80::bbbb:bbbb:bbbb:bbbb%en1 prefixlen 64 scopeid 0x8
```
`/etc/pf.conf`:
```
rdr pass on en1 inet proto tcp from any to any port {80,443} -> 127.0.0.1 port 988
rdr pass on en1 inet6 proto tcp from any to any port {80,443} -> fe80::bbbb:bbbb:bbbb:bbbb port 988
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root }
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root }
```
Then:
```
pfctl -ef /etc/pf.conf
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force --bind-iface6=en1 --bind-linklocal=force
```
Build from source : `make -C /opt/zapret mac`
`ipset/*.sh` scripts work.
### MacOS easy install
`install_easy.sh` supports MacOS
Shipped precompiled binaries are built for 64-bit MacOS with
`-mmacosx-version-min=10.8` option. They should run on all supported MacOS
versions. If no - its easy to build your own. Running `make` automatically
installs developer tools.
**WARNING**:
**Internet sharing is not supported!**
Routing is supported but only manually configured through PF. If you enable
internet sharing tpws stops functioning. When you disable internet sharing you
may lose web site access.
To fix:
```
pfctl -f /etc/pf.conf
```
If you need internet sharing use `tpws` socks mode.
`launchd` is used for autostart (`/Library/LaunchDaemons/zapret.plist`)
Control script: `/opt/zapret/init.d/macos/zapret`
The following commands fork with both tpws and firewall (if `INIT_APPLY_FW=1` in config)
```
/opt/zapret/init.d/macos/zapret start
/opt/zapret/init.d/macos/zapret stop
/opt/zapret/init.d/macos/zapret restart
```
Work with `tpws` only:
```
/opt/zapret/init.d/macos/zapret start-daemons
/opt/zapret/init.d/macos/zapret stop-daemons
/opt/zapret/init.d/macos/zapret restart-daemons
```
Work with PF only:
```
/opt/zapret/init.d/macos/zapret start-fw
/opt/zapret/init.d/macos/zapret stop-fw
/opt/zapret/init.d/macos/zapret restart-fw
```
Reloading PF tables:
```
/opt/zapret/init.d/macos/zapret reload-fw-tables
```
Installer configures `LISTS_RELOAD` in the config so `ipset *.sh` scripts
automatically reload PF tables. Installer creates cron job for `ipset
/get_config.sh`, as in OpenWRT.
start-fw script automatically patches `/etc/pf.conf` inserting there `zapret`
anchors. Auto patching requires pf.conf with apple anchors preserved. If your
`pf.conf` is highly customized and patching fails you will see the warning. Do
not ignore it.
In that case you need to manually insert "zapret" anchors to your `pf.conf`
(keeping the right rule type ordering):
```
rdr-anchor "zapret"
anchor "zapret"
unistall_easy.sh unpatches pf.conf
```
start-fw creates 3 anchor files in `/etc/pf.anchors` :
zapret,zapret-v4,zapret-v6.
- Last 2 are referenced by anchor `zapret`.
- Tables `nozapret`,`nozapret6` belong to anchor `zapret`.
- Tables `zapret`,`zapret-user` belong to anchor `zapret-v4`.
- Tables `zapret6`,`apret6-user` belong to anchor `zapret-v6`.
If an ip version is disabled then corresponding anchor is empty and is not
referenced from the anchor `zapret`. Tables are only created for existing list
files in the `ipset` directory.

476
docs/bsd.txt Normal file
View File

@@ -0,0 +1,476 @@
Поддерживаемые версии
---------------------
FreeBSD 11.x+ , OpenBSD 6.x+, частично MacOS Sierra+
На более старых может собираться, может не собираться, может работать или не работать.
На FreeBSD 10 собирается и работает dvtws. С tpws есть проблемы из-за слишком старой версии компилятора clang.
Вероятно, будет работать, если обновить компилятор.
Возможна прикрутка к последним версиям pfsense без веб интерфейса в ручном режиме через консоль.
Особенности BSD систем
----------------------
В BSD нет nfqueue. Похожий механизм - divert sockets.
Из каталога "nfq" под BSD собирается dvtws вместо nfqws.
Он разделяет с nfqws большую часть кода и почти совпадает по параметрам командной строки.
FreeBSD содержит 3 фаервола : IPFilter, ipfw и Packet Filter (PF). OpenBSD содержит только PF.
Под FreeBSD tpws и dvtws собираются через "make", под OpenBSD - "make bsd", под MacOS - "make mac".
FreeBSD make распознает BSDmakefile , OpenBSD и MacOS - нет. Поэтому там используется отдельный target в Makefile.
Сборка всех исходников : make -C /opt/zapret
divert сокет - внутренний тип сокета ядра BSD. Он не привязывается ни к какому сетевому адресу, не участвует
в обмене данными через сеть и идентифицируется по номеру порта 1..65535. Аналогия с номером очереди NFQUEUE.
На divert сокеты заворачивается трафик посредством правил ipfw или PF.
Если в фаерволе есть правило divert, но на divert порту никто не слушает, то пакеты дропаются.
Это поведение аналогично правилам NFQUEUE без параметра --queue-bypass.
На FreeBSD divert сокеты могут быть только ipv4, хотя на них принимаются и ipv4, и ipv6 фреймы.
На OpenBSD divert сокеты создаются отдельно для ipv4 и ipv6 и работают только с одной версией ip каждый.
На MacOS похоже, что divert сокеты из ядра вырезаны. См подробнее раздел про MacOS.
Отсылка в divert сокет работает аналогично отсылке через raw socket на linux. Передается полностью IP фрейм, начиная
с ip загловка . Эти особенности учитываются в dvtws.
Скрипты ipset/*.sh при наличии ipfw работают с ipfw lookup tables.
Это прямой аналог ipset. lookup tables не разделены на v4 и v6. Они могут содержать v4 и v6 адреса и подсети одновременно.
Если ipfw отсутствует, то действие зависит от переменной LISTS_RELOAD в config.
Если она задана, то выполняется команда из LISTS_RELOAD. В противном случае не делается ничего.
Если LISTS_RELOAD=-, то заполнение таблиц отключается даже при наличии ipfw.
PF может загружать ip таблицы из файла. Чтобы использовать эту возможность следует отключить сжатие gzip для листов
через параметр файла config "GZIP_LISTS=0".
BSD не содержит системного вызова splice. tpws работает через переброску данных в user mode в оба конца.
Это медленнее, но не критически.
Управление асинхронными сокетами в tpws основано на linux-specific механизме epoll.
В BSD для его эмуляции используется epoll-shim - прослойка для эмуляции epoll на базе kqueue.
mdig и ip2net полностью работоспособны в BSD. В них нет ничего системо-зависимого.
FreeBSD
-------
divert сокеты требуют специального модуля ядра ipdivert.
Поместите следующие строки в /boot/loader.conf (создать, если отсутствует) :
-----------
ipdivert_load="YES"
net.inet.ip.fw.default_to_accept=1
-----------
В /etc/rc.conf :
-----------
firewall_enable="YES"
firewall_script="/etc/rc.firewall.my"
-----------
/etc/rc.firewall.my :
-----------
ipfw -q -f flush
-----------
В /etc/rc.firewall.my можно дописывать правила ipfw, чтобы они восстанавливались после перезагрузки.
Оттуда же можно запускать и демоны zapret, добавив в параметры "--daemon". Например так :
-----------
pkill ^dvtws$
/opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2
-----------
Для перезапуска фаервола и демонов достаточно будет сделать : /etc/rc.d/ipfw restart
Краткая инструкция по запуску tpws в прозрачном режиме.
Предполагается, что интерфейс LAN называется em1, WAN - em0.
Для всего трафика :
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
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
Для трафика только на таблицу zapret, за исключением таблицы nozapret :
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
Таблицы zapret, nozapret, ipban создаются скриптами из ipset по аналогии с Linux.
Обновление скриптов можно забить в cron под root :
crontab -e
Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh"
При использовании ipfw tpws не требует повышенных привилегий для реализации прозрачного режима.
Однако, без рута невозможен бинд на порты <1024 и смена UID/GID. Без смены UID будет рекурсия,
поэтому правила ipfw нужно создавать с учетом UID, под которым работает tpws.
Переадресация на порты >=1024 может создать угрозу перехвата трафика непривилегированным
процессом, если вдруг tpws не запущен.
Краткая инструкция по запуску dvtws.
Для всего трафика :
ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0
# required for autottl mode only
ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted recv em0
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
Для трафика только на таблицу zapret, за исключением таблицы nozapret :
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
# required for autottl mode only
ipfw add 100 divert 989 tcp from table\(zapret\) 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
PF в FreeBSD:
Настройка аналогична OpenBSD, но есть важные нюансы.
1) В FreeBSD поддержка PF в tpws отключена по умолчанию. Чтобы ее включить, нужно использовать параметр --enable-pf.
2) Нельзя сделать ipv6 rdr на ::1. Нужно делать на link-local адрес входящего интерфейса.
Смотрите через ifconfig адрес fe80:... и добавляете в правило
3) Синтаксис pf.conf немного отличается. Более новая версия PF.
4) Лимит на количество элементов таблиц задается так : sysctl net.pf.request_maxcount=2000000
5) divert-to сломан. Он работает, но не работает механизм предотвращения зацикливаний.
Кто-то уже написал патч, но в 14-RELEASE проблема все еще есть.
Следовательно, на данный момент работа dvtws через pf невозможна.
/etc/pf.conf
-----------
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::31c:29ff:dee2:1c4d port 988
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988
-----------
/opt/zapret/tpws/tpws --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force
В PF непонятно как делать rdr-to с той же системы, где работает proxy. Вариант с route-to у меня не заработал.
pfsense
-------
pfsense основано на FreeBSD.
pfsense использует фаервол pf, а он имеет проблемы с divert.
К счастью, модули ipfw и ipdivert присутствуют в поставке последних версий pfsense.
Их можно подгрузить через kldload.
В некоторых более старых версиях pfsense требуется изменить порядок фаерволов через sysctl, сделав ipfw первым.
В более новых эти параметры sysctl отсутствуют, но система работает как надо и без них.
В некоторых случаях фаервол pf может ограничивать возможности dvtws, в частности в области фрагментации ip.
Присутствуют по умолчанию правила scrub для реассемблинга фрагментов.
Бинарики из binaries/freebsd-x64 собраны под FreeBSD 11. Они должны работать и на последующих версиях FreeBSD,
включая pfsense. Можно пользоваться install_bin.sh.
Пример скрипта автозапуска лежит в init.d/pfsense. Его следует поместить в /usr/local/etc/rc.d и отредактировать
на предмет правил ipfw и запуска демонов. Есть встроенный редактор edit как более приемлемая альтернатива vi.
Поскольку git отсутствует, копировать файлы удобнее всего через ssh. curl присутствует по умолчанию.
Можно скопировать zip с файлами zapret и распаковать в /opt, как это делается на других системах.
Тогда dvtws нужно запускать как /opt/zapret/nfq/dvtws. Либо скопировать только dvtws в /usr/local/sbin.
Как вам больше нравится.
ipset скрипты работают, крон есть. Можно сделать автообновление листов.
Если вас напрягает бедность имеющегося репозитория, можно включить репозиторий от FreeBSD, который по умолчанию выключен.
Поменяйте no на yes в /usr/local/etc/pkg/repos/FreeBSD.conf
Можно установить весь привычный soft, включая git, чтобы напрямую скачивать zapret с github.
/usr/local/etc/rc.d/zapret.sh (chmod 755)
-----------
#!/bin/sh
kldload ipfw
kldload ipdivert
# for older pfsense versions. newer do not have these sysctls
sysctl net.inet.ip.pfil.outbound=ipfw,pf
sysctl net.inet.ip.pfil.inbound=ipfw,pf
sysctl net.inet6.ip6.pfil.outbound=ipfw,pf
sysctl net.inet6.ip6.pfil.inbound=ipfw,pf
ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0
pkill ^dvtws$
dvtws --daemon --port 989 --dpi-desync=split2
# required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state
pfctl -d ; pfctl -e
-----------
Что касается tpws, то видимо имеется некоторый конфликт двух фаерволов, и правила fwd в ipfw не работают.
Работает перенаправление средствами pf как описано в разделе по FreeBSD.
В pf можно изменять правила только целыми блоками - якорями (anchors). Нельзя просто так добавить или удалить что-то.
Но чтобы какой-то anchor был обработан, на него должна быть ссылка из основного набора правил.
Его трогать нельзя, иначе порушится весь фаервол.
Поэтому придется править код скриптов pfsense. Поправьте /etc/inc/filter.inc следующим образом :
-----------
.................
/* MOD */
$natrules .= "# ZAPRET redirection\n";
$natrules .= "rdr-anchor \"zapret\"\n";
$natrules .= "# TFTP proxy\n";
$natrules .= "rdr-anchor \"tftp-proxy/*\"\n";
.................
-----------
Напишите файл с содержимым anchor-а (например, /etc/zapret.anchor):
-----------
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::20c:29ff:5ae3:4821 port 988
-----------
fe80::20c:29ff:5ae3:4821 замените на ваш link local адрес LAN интерфейса, либо уберите строчку, если ipv6 не нужен.
Добавьте в автозапуск /usr/local/etc/rc.d/zapret.sh :
-----------
pfctl -a zapret -f /etc/zapret.anchor
pkill ^tpws$
tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-http-req=method --split-pos=2
-----------
После перезагрузки проверьте, что правила создались :
-----------
[root@pfSense /]# pfctl -s nat
no nat proto carp all
nat-anchor "natearly/*" all
nat-anchor "natrules/*" all
...................
no rdr proto carp all
rdr-anchor "zapret" all
rdr-anchor "tftp-proxy/*" all
rdr-anchor "miniupnpd" all
[root@pfSense /]# pfctl -s nat -a zapret
rdr pass on em1 inet proto tcp from any to any port = http -> 127.0.0.1 port 988
rdr pass on em1 inet proto tcp from any to any port = https -> 127.0.0.1 port 988
rdr pass on em1 inet6 proto tcp from any to any port = http -> fe80::20c:29ff:5ae3:4821 port 988
rdr pass on em1 inet6 proto tcp from any to any port = https -> fe80::20c:29ff:5ae3:4821 port 988
-----------
Так же есть более элегантный способ запуска tpws через @reboot в cron и правило перенаправления в UI.
Это позволит не редактировать код pfsense.
OpenBSD
-------
В tpws бинд по умолчанию только на ipv6. для бинда на ipv4 указать "--bind-addr=0.0.0.0"
Используйте --bind-addr=0.0.0.0 --bind-addr=:: для достижения того же результата, как в других ОС по умолчанию.
(лучше все же так не делать, а сажать на определенные внутренние адреса или интерфейсы)
tpws для проходящего трафика :
/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
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
В PF непонятно как делать rdr-to с той же системы, где работает proxy. Вариант с route-to у меня не заработал.
Поддержка rdr-to реализована через /dev/pf, поэтому прозрачный режим требует root.
dvtws для всего трафика :
/etc/pf.conf
------------
pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state
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 для трафика только на таблицу zapret, за исключением таблицы nozapret :
/etc/pf.conf
------------
set limit table-entries 2000000
table <zapret> file "/opt/zapret/ipset/zapret-ip.txt"
table <zapret-user> file "/opt/zapret/ipset/zapret-ip-user.txt"
table <nozapret> file "/opt/zapret/ipset/zapret-ip-exclude.txt"
pass out quick on em0 inet proto tcp to <nozapret> port {80,443}
pass in quick on em0 inet proto tcp from <zapret> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret> port {80,443} no state
pass out quick on em0 inet proto tcp to <zapret> port {80,443} divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} no state
pass out quick on em0 inet proto tcp to <zapret-user> port {80,443} divert-packet port 989 no state
table <zapret6> file "/opt/zapret/ipset/zapret-ip6.txt"
table <zapret6-user> file "/opt/zapret/ipset/zapret-ip-user6.txt"
table <nozapret6> file "/opt/zapret/ipset/zapret-ip-exclude6.txt"
pass out quick on em0 inet6 proto tcp to <nozapret6> port {80,443}
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} no state
pass out quick on em0 inet6 proto tcp to <zapret6> port {80,443} divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} no state
pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-packet port 989 no state
------------
pfctl -f /etc/pf.conf
./dvtws --port=989 --dpi-desync=split2
divert-packet автоматически вносит обратное правило для перенаправления.
Трюк с no state и in правилом позволяет обойти эту проблему, чтобы напрасно не гнать массивный трафик через dvtws.
В OpenBSD dvtws все фейки отсылает через divert socket, поскольку эта возможность через raw sockets заблокирована.
Видимо pf автоматически предотвращает повторный заворот diverted фреймов, поэтому проблемы зацикливания нет.
OpenBSD принудительно пересчитывает tcp checksum после divert, поэтому скорее всего
dpi-desync-fooling=badsum у вас не заработает. При использовании этого параметра
dvtws предупредит о возможной проблеме.
Скрипты из ipset не перезагружают таблицы в PF по умолчанию.
Чтобы они это делали, добавьте параметр в /opt/zapret/config :
LISTS_RELOAD="pfctl -f /etc/pf.conf"
Более новые версии pfctl понимают команду перезагрузить только таблицы : pfctl -Tl -f /etc/pf.conf
Но это не относится к OpenBSD 6.8. В новых FreeBSD есть.
Не забудьте выключить сжатие gzip :
GZIP_LISTS=0
Если в вашей конфигурации какого-то файла листа нет, то его необходимо исключить из правил PF.
Если вдруг листа нет, и он задан в pf.conf, будет ошибка перезагрузки фаервола.
После настройки обновление листов можно поместить в cron :
crontab -e
дописать строчку : 0 12 */2 * * /opt/zapret/ipset/get_config.sh
MacOS
-----
Иначально ядро этой ОС "darwin" основывалось на BSD, потому в ней много похожего на другие версии BSD.
Однако, как и в других массовых коммерческих проектах, приоритеты смещаются в сторону от оригинала.
Яблочники что хотят, то и творят.
Раньше был ipfw, потом его убрали, заменили на PF.
Есть сомнения, что divert сокеты в ядре остались. Попытка создать divert socket не выдает ошибок,
но полученный сокет ведет себя точно так же, как raw, со всеми его унаследованными косяками + еще яблочно специфическими.
В PF divert-packet не работает. Простой grep бинарика pfctl показывает, что там нет слова "divert",
а в других версиях BSD оно есть. dvtws собирается, но совершенно бесполезен.
tpws удалось адаптировать, он работоспособен. Получение адреса назначения для прозрачного прокси в PF (DIOCNATLOOK)
убрали из заголовков в новых SDK, сделав фактически недокументированным.
В tpws перенесены некоторые определения из более старых версий яблочных SDK. С ними удалось завести прозрачный режим.
Однако, что будет в следующих версиях угадать сложно. Гарантий нет.
Еще одной особенностью PF в MacOS является проверка на рута в момент обращения к /dev/pf, чего нет в остальных BSD.
tpws по умолчанию сбрасывает рутовые привилегии. Необходимо явно указать параметр --user=root.
В остальном PF себя ведет похоже на FreeBSD. Синтаксис pf.conf тот же.
На MacOS работает редирект как с проходящего трафика, так и с локальной системы через route-to.
Поскольку tpws вынужден работать под root, для исключения рекурсии приходится пускать исходящий от root трафик напрямую.
Отсюда имеем недостаток : обход DPI для рута работать не будет.
Если вы пользуетесь MaсOS в качестве ipv6 роутера, то нужно будет решить вопрос с регулярно изменяемым link-local адресом.
С некоторых версий MacOS использует по умолчанию постоянные "secured" ipv6 адреса вместо генерируемых на базе MAC адреса.
Все замечательно, но есть одна проблема. Постоянными остаются только global scope адреса.
Link locals периодически меняются. Смена завязана на системное время. Перезагрузки адрес не меняют,
Но если перевести время на день вперед и перезагрузиться - link local станет другим. (по крайней мере в vmware это так)
Информации по вопросу крайне мало, но тянет на баг. Не должен меняться link local. Скрывать link local не имеет смысла,
а динамический link local нельзя использовать в качестве адреса шлюза.
Проще всего отказаться от "secured" адресов.
Поместите строчку "net.inet6.send.opmode=0" в /etc/sysctl.conf. Затем перезагрузите систему.
Все равно для исходящих соединений будут использоваться temporary адреса, как и в других системах.
Или вам идея не по вкусу, можно прописать дополнительный статический ipv6 из диапазона fc00::/7 -
выберите любой с длиной префикса 128. Это можно сделать в системных настройках, создав дополнительный адаптер на базе
того же сетевого интерфейса, отключить в нем ipv4 и вписать статический ipv6. Он добавится к автоматически настраеваемым.
Настройка tpws на macos в прозрачном режиме только для исходящих запросов :
/etc/pf.conf
------------
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root }
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root }
------------
pfctl -ef /etc/pf.conf
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force
Настройка tpws на macos роутере в прозрачном режиме, где en1 - LAN.
ifconfig en1 | grep fe80
inet6 fe80::bbbb:bbbb:bbbb:bbbb%en1 prefixlen 64 scopeid 0x8
/etc/pf.conf
------------
rdr pass on en1 inet proto tcp from any to any port {80,443} -> 127.0.0.1 port 988
rdr pass on en1 inet6 proto tcp from any to any port {80,443} -> fe80::bbbb:bbbb:bbbb:bbbb port 988
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root }
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root }
------------
pfctl -ef /etc/pf.conf
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force --bind-iface6=en1 --bind-linklocal=force
Сборка : make -C /opt/zapret mac
Скрипты получения листов ipset/*.sh работают.
Если будете пользоваться ipset/get_combined.sh, нужно установить gnu grep через brew.
Имеющийся очень старый и безумно медленный с оцией -f.
MacOS простая установка
-----------------------
В MacOS поддерживается install_easy.sh
В комплекте идут бинарики, собраные под 64-bit с опцией -mmacosx-version-min=10.8.
Они должны работать на всех поддерживаемых версиях macos.
Если вдруг не работают - можно собрать свои. Developer tools ставятся автоматом при запуске make.
!! Internet sharing средствами системы НЕ ПОДДЕРЖИВАЕТСЯ !!
Поддерживается только роутер, настроенный своими силами через PF.
Если вы вдруг включили шаринг, а потом выключили, то доступ к сайтам может пропасть совсем.
Лечение : pfctl -f /etc/pf.conf
Если вам нужен шаринг интернета, лучше отказаться от прозрачного режима и использовать socks.
Для автостарта используется launchd (/Library/LaunchDaemons/zapret.plist)
Управляющий скрипт : /opt/zapret/init.d/macos/zapret
Следующие команды работают с tpws и фаерволом одновременно (если INIT_APPLY_FW=1 в config)
/opt/zapret/init.d/macos/zapret start
/opt/zapret/init.d/macos/zapret stop
/opt/zapret/init.d/macos/zapret restart
Работа только с tpws :
/opt/zapret/init.d/macos/zapret start-daemons
/opt/zapret/init.d/macos/zapret stop-daemons
/opt/zapret/init.d/macos/zapret restart-daemons
Работа только с PF :
/opt/zapret/init.d/macos/zapret start-fw
/opt/zapret/init.d/macos/zapret stop-fw
/opt/zapret/init.d/macos/zapret restart-fw
Перезагрузка всех IP таблиц из файлов :
/opt/zapret/init.d/macos/zapret reload-fw-tables
Инсталятор настраивает LISTS_RELOAD в config, так что скрипты ipset/*.sh автоматически перезагружают IP таблицы в PF.
Автоматически создается cron job на ipset/get_config.sh, по аналогии с openwrt.
При start-fw скрипт автоматически модицифирует /etc/pf.conf, вставляя туда anchors "zapret".
Модификация расчитана на pf.conf, в котором сохранены дефолтные anchors от apple.
Если у вас измененный pf.conf и модификация не удалась, об этом будет предупреждение. Не игнорируйте его.
В этом случае вам нужно вставить в свой pf.conf (в соответствии с порядком типов правил) :
rdr-anchor "zapret"
anchor "zapret"
При деинсталяции через uninstall_easy.sh модификации pf.conf убираются.
start-fw создает 3 файла anchors в /etc/pf.anchors : zapret,zapret-v4,zapret-v6.
Последние 2 подключаются из anchor "zapret".
Таблицы nozapret,nozapret6 принадлежат anchor "zapret".
Таблицы zapret,zapret-user - в anchor "zapret-v4".
Таблицы zapret6,zapret6-user - в anchor "zapret-v6".
Если какая-то версия протокола отключена - соответствующий anchor пустой и не упоминается в anchor "zapret".
Таблицы и правила создаются только на те листы, которые фактически есть в директории ipset.
MacOS вариант custom
--------------------
Так же как и в других системах, поддерживаемых в простом инсталяторе, можно создавать свои custom скрипты.
Расположение : /opt/zapret/init.d/macos/custom
zapret_custom_daemons() получает в $1 "0" или "1". "0" - stop, "1" - start
custom firewall отличается от linux варианта.
Вместо заполнения iptables вам нужно сгенерировать правила для zapret-v4 и zapret-v6 anchors и выдать их в stdout.
Это делается в функциях zapret_custom_firewall_v4() и zapret_custom_firewall_v6().
Определения таблиц заполняются основным скриптом - вам это делать не нужно.
Можно ссылаться на таблицы zapret и zapret-user в v4, zapret6 и zapret6-user.
Cм. пример в файле custom-tpws

97
docs/bsdfw.txt Normal file
View File

@@ -0,0 +1,97 @@
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
ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0
; required for autottl mode
ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted recv em0
; udp
ipfw add 100 divert 989 udp from any to any 443 out not diverted 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 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} flags SA/SA divert-packet port 989 no state
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 <zapret> file "/opt/zapret/ipset/zapret-ip.txt"
table <zapret-user> file "/opt/zapret/ipset/zapret-ip-user.txt"
table <nozapret> file "/opt/zapret/ipset/zapret-ip-exclude.txt"
pass out quick on em0 inet proto tcp to <nozapret> port {80,443}
pass in quick on em0 inet proto tcp from <zapret> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret> port {80,443} no state
pass out quick on em0 inet proto tcp to <zapret> port {80,443} divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} no state
pass out quick on em0 inet proto tcp to <zapret-user> port {80,443} divert-packet port 989 no state
table <zapret6> file "/opt/zapret/ipset/zapret-ip6.txt"
table <zapret6-user> file "/opt/zapret/ipset/zapret-ip-user6.txt"
table <nozapret6> file "/opt/zapret/ipset/zapret-ip-exclude6.txt"
pass out quick on em0 inet6 proto tcp to <nozapret6> port {80,443}
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} no state
pass out quick on em0 inet6 proto tcp to <zapret6> port {80,443} divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} flags SA/SA divert-packet port 989 no state
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} no state
pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-packet port 989 no state

325
docs/changes.txt Normal file
View File

@@ -0,0 +1,325 @@
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.
v52
autohostlist mode
v53
nfqws: tcp session reassemble for TLS ClientHello
v54
tpws: out of band send when splitting (--oob)
nfqws: autottl
nfqws: datanoack fooling
nftables: use POSTNAT path for tcp redirections to allow NAT-breaking strategies. use additional mark bit DESYNC_MARK_POSTNAT.
v55
tpws: incompatible oob parameter change. it doesn't take oob byte anymore. instead it takes optional protocol filter - http or tls.
the same is done with disorder. oob byte can be specified in parameter --oob-data.
blockcheck: quick mode, strategy order optimizations, QUIC protocol support
nfqws: syndata desync mode
v56
tpws: mss fooling
tpws: multi thread resolver. eliminates blocks related to hostname resolve.
v57
tpws: --nosplice option
nfqws: postnat fixes
nfqws: --dpi-desync-start option
nfqws: packet delay for kyber TLS and QUIC
nfqws: --dpi-desync-retrans obsolete
nfqws: --qnum is mandatory, no more default queue 0
v58
winws
v59
tpws: --split-tls
tpws: --tlsrec=sniext
nfqws: --dpi-desync-split-http-req, --dpi-desync-split-tls. multi segment TLS support for split.
blockcheck: mdig dns cache
v60
blockcheck: port block test, partial ip block test
nfqws: seqovl split/disorder modes
v61
C code cleanups
dvtws: do not use raw sockets. use divert.
nfqws,tpws: detect TLS 1.2 ClientHello from very old libraries with SSL 3.0 version in record layer
nfqws,tpws: debug log to file and syslog
tpws: --connect-bind-addr option
tpws: log local endpoint (including source port number) for remote leg
v62:
tpws: connection close logic rewrite. tcp user timeout parameters for local and remote leg.
nfqws: multi-strategy
v63:
tpws: multi-strategy
v64:
blockcheck: warn if dpi bypass software is already running
blockcheck: TPWS_EXTRA, NFQWS_EXTRA
init.d: multiple custom scripts

View File

@@ -0,0 +1,42 @@
How to compile native programs for use in openwrt
-------------------------------------------------
1) <fetch correct version of openwrt>
cd ~
<chaos calmer>
git clone git://git.openwrt.org/15.05/openwrt.git
<barrier breaker>
git clone git://git.openwrt.org/14.07/openwrt.git
<trunk>
git clone git://git.openwrt.org/openwrt.git
cd openwrt
2) ./scripts/feeds update -a
./scripts/feeds install -a
3) #add zapret packages to build root
#copy package descriptions
copy compile/openwrt/* to ~/openwrt
#copy source code of tpws
copy tpws to ~/openwrt/package/zapret/tpws
#copy source code of nfq
copy nfq to ~/openwrt/package/zapret/nfq
#copy source code of ip2net
copy ip2net to ~/openwrt/package/zapret/ip2net
4) make menuconfig
#select your target architecture
#select packages Network/Zapret/* as "M"
5) make toolchain/compile
6) make package/tpws/compile
make package/nfqws/compile
make package/ip2net/compile
make package/mdig/compile
7) find bin -name tpws*.ipk
#take your tpws*.ipk , nfqws*.ipk , ip2net*.ipk, mdig*.ipk from there

View File

@@ -0,0 +1,32 @@
#
include $(TOPDIR)/rules.mk
PKG_NAME:=ip2net
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/ip2net
SECTION:=net
CATEGORY:=Network
TITLE:=ip2net
SUBMENU:=Zapret
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./ip2net/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS)
endef
define Package/ip2net/install
$(INSTALL_DIR) $(1)/opt/zapret/ip2net
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ip2net $(1)/opt/zapret/ip2net
endef
$(eval $(call BuildPackage,ip2net))

View File

@@ -0,0 +1 @@
Copy "ip2net" folder here !

View File

@@ -0,0 +1,32 @@
#
include $(TOPDIR)/rules.mk
PKG_NAME:=mdig
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/mdig
SECTION:=net
CATEGORY:=Network
TITLE:=mdig
SUBMENU:=Zapret
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./mdig/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS)
endef
define Package/mdig/install
$(INSTALL_DIR) $(1)/opt/zapret/mdig
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mdig $(1)/opt/zapret/mdig
endef
$(eval $(call BuildPackage,mdig))

View File

@@ -0,0 +1 @@
Copy "mdig" folder here !

View File

@@ -0,0 +1,34 @@
#
include $(TOPDIR)/rules.mk
PKG_NAME:=nfqws
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/nfqws
SECTION:=net
CATEGORY:=Network
TITLE:=nfqws
SUBMENU:=Zapret
DEPENDS:=+libnetfilter-queue +libcap +zlib
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./nfq/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS)
endef
define Package/nfqws/install
$(INSTALL_DIR) $(1)/opt/zapret/nfq
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nfqws $(1)/opt/zapret/nfq
endef
$(eval $(call BuildPackage,nfqws))

View File

@@ -0,0 +1 @@
Copy "nfq" folder here !

View File

@@ -0,0 +1,33 @@
#
include $(TOPDIR)/rules.mk
PKG_NAME:=tpws
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/tpws
SECTION:=net
CATEGORY:=Network
TITLE:=tpws
SUBMENU:=Zapret
DEPENDS:=+zlib +libcap
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./tpws/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS)
endef
define Package/tpws/install
$(INSTALL_DIR) $(1)/opt/zapret/tpws
$(INSTALL_BIN) $(PKG_BUILD_DIR)/tpws $(1)/opt/zapret/tpws
endef
$(eval $(call BuildPackage,tpws))

View File

@@ -0,0 +1 @@
Copy "tpws" folder here !

63
docs/iptables.txt Normal file
View File

@@ -0,0 +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 dpi desync attack :
iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -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
# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1
iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:12 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I PREROUTING -p tcp -m multiport --sports 80,443 -m connbytes --connbytes-dir=reply --connbytes-mode=packets --connbytes 1:6 -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

282
docs/manual_setup.txt Normal file
View File

@@ -0,0 +1,282 @@
Пример ручной установки на 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
Создать конфиг по умолчанию :
cp /opt/zapret/config.default /opt/zapret/config
Настроить параметры согласно разделу "Выбор параметров".
Создать user листы по умолчанию :
cp /opt/zapret/ipset/zapret-hosts-user-exclude.txt.default /opt/zapret/ipset/zapret-hosts-user-exclude.txt
echo nonexistent.domain >/opt/zapret/ipset/zapret-hosts-user.txt
touch /opt/zapret/ipset/zapret-hosts-user-ipban.txt
Создать ссылку на 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 <package_name>
Пакеты собираются из исходников.
Требуются все те же 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 <zapret.tar.gz
На роутере
cd /tmp
nc <linux_system_ip> 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
Создать конфиг по умолчанию :
cp /opt/zapret/config.default /opt/zapret/config
Настроить параметры согласно разделу "Выбор параметров".
Создать user листы по умолчанию :
cp /opt/zapret/ipset/zapret-hosts-user-exclude.txt.default /opt/zapret/ipset/zapret-hosts-user-exclude.txt
echo nonexistent.domain >/opt/zapret/ipset/zapret-hosts-user.txt
touch /opt/zapret/ipset/zapret-hosts-user-ipban.txt
Удалить старые листы, если они были созданы ранее :
/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.
рипт из /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.
Работа с листами РКН невозможна в принципе.

32
docs/nftables.txt Normal file
View File

@@ -0,0 +1,32 @@
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}" ct original packets 1-12 queue num 200 bypass
nft add rule inet ztest post udp dport 443 ct original packets 1-4 queue num 200 bypass
# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1
nft add chain inet ztest pre "{type filter hook prerouting priority filter;}"
nft add rule inet ztest pre tcp sport "{80,443}" ct reply packets 1-4 queue num 200 bypass
show rules : nft list table inet ztest
delete table : nft delete table inet ztest

120
docs/nftables_notes.txt Normal file
View File

@@ -0,0 +1,120 @@
nftables - это технология, пришедшая на замену iptables.
В ней собрали все, что относилось к различным iptables. А их немало. iptables, ip6tables, ebtables, arptables, ipset.
Весь код из разрозненных, но похожих компонент, собрали в одно целое с единым синтаксисом.
Добавили различные конструкции языка, позволяющие писать правила более лаконично, не повторяя одни и те же команды с небольшими различиями.
На nftables можно сделать почти все, что можно было сделать на iptables. Есть то, что можно сделать на nftables, но нельзя на iptables.
Есть и наоборот.
К сожалению, не обошлось и без боли.
Главная боль N1. Очень серьезная, актуальная для openwrt, и решения не видно.
ipset-ы позволяли загонять пересекающиеся интервалы ip адресов или подсетей.
nftables sets это не позволяют. Любое пересечение вызывает ошибку.
Есть auto-merge, но это работает только в user mode в процессе nft, при условии, что весь блок адресов загоняется одной командой
и нет пересечений с уже имеющимся контентом в set.
Это не было бы критической проблемой, поскольку скрипты zapret и так загоняют ipset целиком.
Проблема в катастрофическом расходе памяти при операции загона больших интервальных листов, то есть с подсетями и диапазонами.
Чтобы загнать 100000 ipv4 записей, едва хватает 300 Mb памяти устройства.
При успехе операции в ядре список столько не занимает, но суть дела это не меняет.
Для традиционных linux систем это не проблема, но почти все роутеры загнутся.
Приемлемого решения не просматривается.
Сделать записи непересекающимися в листах - задача непростая. Потребуется переписать алгоритм auto-merge из nft,
но с пониженным расходом памяти.
Загонять записи по одному отдельными вызовами nft, игнорируя ошибки, займет вечность.
Загонять блоком отдельных команд, игнорируя ошибки, - nft такого не умеет. Похоже, при любой ошибке происходит откат всего скрипта.
К тому же при таком подходе будут неточности в итоговом результате.
Swap позволяет немного сгладить проблему, но лишь незначительно.
Скажем, если вдруг list загоняется без ошибок с 300 Mb памяти и с падением на 256 Mb, то swap спасает.
Если памяти становится 200 Mb, то swap уже не спасет. Все равно вызывается OOM killer, заодно убивая и другие процессы, кроме nft,
а это уже совсем плохо. Может быть убито что-то важное.
Боль N2, не смертельная, но тоже не айс.
Какие-то нерациональные алгоритмы разбора таблиц в nft.
Например, есть 1 большой set на 100000 элементов и 1 маленький на 2 элемента.
Чтобы просто пролистать мелкий set или добавить туда еще что-то nft будет мусолить несколько секунд.
Что он делает за это время ? Тащит из ядра огромный блоб, в котором все в куче, и разбирает его, чтобы выделить искомую мелочь ?
В какой-то мере удается это сгладить, обьединяя несколько команд в единый скрипт.
Боль N3
Система nftables построена на виртуальной машине. Правила, которые вы пишите, переводятся в псевдокод VM.
Чтобы потом их показать , nft декомпилирует код и переводит в читаемый язык.
Это довольно сложно, и регулярно случаются баги, связанные с неверным отображением.
Кроме этого, часто встречаются и баги парсера.
Например, все версии nft вплоть до 1.0.1 имеют баг, который не разрешает названия интерфейсов в кавычках в
определении flowtable. Без кавычек нельзя вставить интерфейсы , имя которых начинается с цифры.
OpenWRT решает эту проблему отдельным патчем в snapshot версии, но на традиционных системах и в openwrt 21.x- его нет.
Почему бы не наплевать на интерфейсы, начинающиеся с цифры ? Потому что для openwrt 6to4-6to4, 6in4-he-net - обычное явление.
На текущий момент этой проблемы в openwrt уже нет, если использовать актуальную версию.
Но тем не менее, хоть nft и давно перешел отметку 1.0, всякая мелочь, особенно на не совсем стандартных правилах,
регулярно всплывает. Потому чем новее у вас будет версия nft, тем больше там выловлено проблем.
Здесь обновления важны, чтобы потом не мучаться из-за давно исправленного велосипеда.
Боль N4
Невозможно , не копаясь в других таблицах и хуках, ничего не зная об их содержании, предотвратить DROP или REJECT.
Нельзя написать такое правило, которое что-то важное ACCEPTнет, игнорируя остальные хуки во всех таблицах.
Если у вас есть какой-то фаервол, и он что-то дропает, то как от этого отказаться, если надо временно что-то принять ?
Это особенность netfilter, он так работает, но в iptables есть лишь стандартные таблицы с их хуками, куда можно
вставить ACCEPT. Здесь хуков может быть сколько угодно в каких угодно таблицах.
Эта проблема частично ломает кайф от независимого управления таблицами.
Плюс N1, главный
iptables хороши, когда ими пользуется кто-то один. Иначе это проходной двор.
Когда есть система управления фаерволом, то приходится как-то к ней прикручиваться, чтобы не нарушить ее работу
и управлять правилами синхронно. Нужно уметь внести и удалить отдельные правила когда это нужно, не трогая все остальное.
Некоторые системы управления фаерволом вообще не предполагают, чтобы кто-то еще лез в iptables, и это очень сильно портит жизнь.
У iptables есть предопределенный набор хуков netfilter с фиксированным приоритетом.
В nftables хуков можно создать неограниченное количество с выбранным приоритетом, управляя ими независимо в отдельных таблицах.
Система управления фаерволом может работать в одной таблице (fw4 в случае openwrt) и не трогать все остальное.
zapret может работать в другой таблице и не трогать систему управления фаерволом. Они друг другу не мешают.
Это снимает множество боли.
Но есть и исключение. nfset-ы - аналог ipset-ов - нельзя использовать из другой таблицы. Потому если вам нужен ipset,
создаваемый zapret скриптами, вам понадобится писать правила в той же таблице. Но нет никакой необходимости влезать в цепочки zapret.
Создаете свои цепочки и хуки и делаете в них что угодно.
Плюс N2
Возможность выбора приоритета хука позволяет легко решить проблему хаотической и принудительной дефрагментацией L3 ipv6,
без танцев с загрузкой модулей ядра со специальными параметрами или перекомпиляцией nftables-nft.
Это же позволяет перехватить трафик после SNAT/MASQUERADE, что на iptables невозможно.
Атаки на проходящий трафик, ломающие NAT, крайне затруднены на iptables.
Плюс N3
Наличие множеств (anonymous/named sets) позволяет не писать кучу однообразных правил там, где в iptables их пришлось бы написать.
Плюс N4
Если у вас есть nftables, то там наверняка есть уже все или почти все.
Нет кучи разных модулей ядра и .so плагинов для iptables user-mode процесса.
Отдельные модули ядра есть, но их меньше, чем в iptables, и openwrt их делит на меньшее число пакетов, большинство из которых
и так ставятся по умолчанию. user-mode процесс nft и вовсе неделим. EXE-шник + lib.
Плюс N5
Пишут, что nftables работают быстрее. Но это не точно и зависит от много чего.
В целом - чем меньше правил, тем выше скорость. Но в nftables правил можно писать меньше, значит скрость тоже может быть выше.
У разработчиков есть идея перевести backend nftables на BPF, а это наверняка будет существенно быстрее.
Выводы
Без больших листов все почти прекрасно. Но большие ip листы убивают все. Не для домашних это роутеров.
А ipset-ы к nftables не прикрутить.
Зато есть возможность задействовать более продвинутые атаки, конфликтующие с NAT, которые на iptables могут быть невозможны.
Делать нечего. Openwrt отошел от iptables. С этим придется как-то жить.
Поэтому пришлось сделать для openwrt поддержку и iptables, и nftables (только с версии openwrt 21.xx, в более старых будут проблемы).
iptables можно задействовать на любой openwrt версии.
Если используется fw3, применяется старый механизм интеграции в fw3.
Если он не используется, то правилами iptables управляем как в традиционных linux системах - то есть с возможностью
запуска и остановки, а скрипт запуска вносит в том числе и правила iptables.
На новых openwrt возможно снести nftables и firewall4 и установить firewall3 и iptables.
Если вам никак без больших ip листов на слабой системе, это может быть единственным спасением.

141
docs/quick_start.txt Normal file
View File

@@ -0,0 +1,141 @@
Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt.
Предупреждение : не пишите в issue вопросы типа "как скопировать файл", "как скачать", "как запустить", ...
То есть все , что касается базовых навыков обращения с ОС linux. Эти вопросы буду закрывать сразу.
Если у вас подобные вопросы возникают, рекомендую не использовать данный софт или искать помощь где-то в другом месте.
То же самое могу сказать тем, кто хочет нажать 1 кнопку, чтобы все заработало, и совсем не хочет читать и изучать.
Увы, такое не подвезли и не подвезут. Ищите другие более простые методы обхода. Этот метод не для рядового пользователя.
Обход DPI является хакерской методикой. Под этим словом понимается метод, которому сопротивляется окружающая среда,
которому автоматически не гарантирована работоспособность в любых условиях и на любых ресурсах,
требуется настройка под специфические условия у вашего провайдера. Условия могут меняться со временем,
и методика может начинать или переставать работать, может потребоваться повторный анализ ситуации.
Могут обнаруживаться отдельные ресурсы, которые заблокированы иначе, и которые не работают или перестали работать.
Могут и сломаться отдельные незаблокированные ресурсы.
Поэтому очень желательно иметь знания в области сетей, чтобы иметь возможность проанализировать техническую ситуацию.
Не будет лишним иметь обходные каналы проксирования трафика на случай, если обход DPI не помогает.
Будем считать, что у вас есть система на базе традиционного linux или openwrt.
Если у вас традиционный linux - задача обойти блокировки только на этой системе, если openwrt - обойти блокировки
для подключенных устройств. Это наиболее распространенный случай.
1) Чтобы процедура установки сработала в штатном режиме на openwrt, нужно раcсчитывать на свободное место около 1-2 Mb
для установки самого zapret и необходимых дополнительных пакетов.
Если места мало и нет возможности его увеличить за счет extroot, возможно придется отказаться от варианта
простой установки и прикручивать в ручном режиме без имеющихся скриптов запуска, либо попробовать засунуть требуемые
zapret дополнительные пакеты в сжатый образ squashfs с помощью image builder и перешить этим вариантом роутер.
См docs/manual_setup.txt , docs/readme.txt .
2) Скачайте zip архив проекта с github в /tmp, распакуйте его там,
либо клонируйте проект через : git clone --depth 1 https://github.com/bol-van/zapret
3) Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и сам zapret.
Гарантированно уберет zapret скрипт uninstall_easy.sh.
4) Если вы работаете в виртуальной машине, необходимо использовать соединение с сетью в режиме bridge. nat не подходит
5) Выполните однократные действия по установке требуемых пакетов в ОС и настройке бинариков правильной архитектуры
install_bin.sh
install_prereq.sh
Вас могут спросить о типе фаервола (iptables/nftables) и использовании ipv6. Это нужно для установки
правильных пакетов в ОС, чтобы не устанавливать лишнее.
6) Запустите blockcheck.sh. blockcheck.sh в начале проверяет DNS. Если выводятся сообщения о подмене адресов, то
первым делом нужно решить эту проблему, иначе ничего не будет работать.
Решение проблемы DNS выходит за рамки проекта. Обычно она решается либо заменой DNS серверов
от провайдера на публичные (1.1.1.1, 8.8.8.8), либо в случае перехвата провайдером обращений
к сторонним серверам - через специальные средства шифрования DNS запросов, такие как dnscrypt, DoT, DoH.
Еще один эффективный вариант - использовать ресолвер от yandex 77.88.8.88 на нестандартном порту 1253.
Многие провайдеры не анализируют обращения к DNS на нестандартных портах.
Проверить работает ли этот вариант можно так :
dig -p 53 @77.88.8.88 rutracker.org
dig -p 1253 @77.88.8.88 rutracker.org
Если DNS действительно подменяется, и ответ на эти 2 команды разный, значит метод вероятно работает.
В openwrt DNS на нестандартном порту можно прописать в /etc/config/dhcp таким способом :
config dnsmasq
.............
list server '77.88.8.88#1253'
Если настройки IP и DNS получаются автоматически от провайдера, в /etc/config/network
найдите секцию интерфейса 'wan' и сделайте так :
config interface 'wan'
.............
option peerdns '0'
/etc/init.d/network restart
/etc/init.d/dnsmasq restart
Если это не подходит, можно перенаправлять обращения на udp и tcp порты 53 вашего DNS сервера на 77.88.8.88:1253 средствами
iptables/nftables. В /etc/resolv.conf нельзя прописать DNS на нестандартном порту.
7) blockcheck позволяет выявить рабочую стратегию обхода блокировок
По результатам blockcheck нужно понять какой вариант будете использовать : nfqws или tpws
И запомнить найденные стратегии.
Следует понимать, что blockcheck проверяет доступность только конкретного домена, который вы вводите в начале.
Вероятно, все остальные домены блокированы подобным образом, но не факт.
В большинстве случаев можно обьединить несколько стратегий в одну универсальную, но для этого необходимо понимать
"что там за буковки". Если вы в сетях слабо разбираетесь, это не для вас. В противном случае читайте readme.txt.
zapret не может пробить блокировку по IP адресу
Для проверки нескольких доменов вводите их через пробел.
Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у вас может быть несколько маршрутов
с различной длиной по ХОПам, с DPI на разных хопах. Приходится преодолевать целый зоопарк DPI,
которые еще и включаются в работу хаотичным образом или образом, зависящим от направления (IP сервера).
blockcheck не всегда может выдать вам в итогах оптимальную стратегию, которую надо просто переписать в настройки.
В некоторых случаях надо реально думать что происходит, анализируя результат на разных стратегиях.
Если вы применяете большой TTL, чтобы достать до магистрала, то не лишним будет добавить дополнительный ограничитель
--dpi-desync-fooling, чтобы не сломать сайты на более коротких дистанциях.
md5sig наиболее совместим, но работает только на linux серверах.
badseq может работать только на https и не работать на http.
Чтобы выяснить какие дополнительные ограничители работают, смотрите результат теста аналогичных стратегий без TTL
с каждым из этих ограничителей.
При использовании autottl следует протестировать как можно больше разных доменов. Эта техника
может на одних провайдерах работать стабильно, на других потребуется выяснить при каких параметрах
она стабильна, на третьих полный хаос, и проще отказаться.
Если используются методы нулевой фазы десинхронизации (--mss, --wssize, --dpi-desync=syndata) и режим фильтрации hostlist,
то все параметры, относящиеся к этим методам, следует помещать не в основные параметры (например, NFQWS_OPT_DESYNC),
а в suffix (NFQWS_OPT_DESYNC_SUFFIX). Чтобы не ошибиться, можно их продублировать и там, и там.
Иначе они могут не работать.
8) Запустите install_easy.sh.
Выберите nfqws или tpws, затем согласитесь на редактирование параметров.
Откроется редактор, куда впишите найденные стратегии.
Для nfqws отдельно настраиваются стратегии на http и https для ipv4 и ipv6.
То есть по максимуму 4 разных варианта.
NFQWS_OPT_DESYNC - это общая установка, которая применяется, если какой-либо уточняющий параметр не задан
NFQWS_OPT_DESYNC_HTTP и NFQWS_OPT_DESYNC_HTTPS заменяют стратегию для http и https.
Если у вас включен ipv6, то они так же будут применены и к ipv6. Если для ipv6 нужна другая стратегия,
то можно задать уточняющие параметры NFQWS_OPT_DESYNC_HTTP6 и NFQWS_OPT_DESYNC_HTTPS6.
Если стратегии для ipv4 и ipv6 отличаются лишь ttl, то в целях экономии ресурсов роутера (меньше процессов nfqws)
следует отказаться от использования специфических для ipv6 установок. Вместо них использовать параметры
--dpi-desync-ttl и --dpi-desync-ttl6 в общих установках. Таким способом можно заставить один процесс nfqws
обрабатывать трафик на ipv4 и на ipv6 с разным ttl.
Важным вопросом является вопрос о поддержке http keep alive.
Отвечайте N. Если вдруг на http сайтах будут хаотические сбои типа то загружается, то заглушка или сброс,
попробуйте включить поддержку keep alive. Но просто "на всякий случай" не включайте - это увеличит нагрузку на роутер.
Если это не помогает, или хаотичное поведение наблюдается и на https, то еще раз прогоните blockcheck
с установленным числом попыток проверки не менее 5. Возможно, ваш провайдер использует балансировку нагрузки,
где на разных путях установлен разный DPI.
9) На все остальные вопросы install_easy.sh отвечайте согласно выводимой аннонтации.
10) Если ломаются отдельные незаблокированные ресурсы, следует вносить их в исключения, либо пользоваться ограничивающим
ipset или хост листом. Читайте основной талмуд readme.txt ради подробностей.
Это минимальная инструкция, чтобы соориентироваться с чего начать. Однако, это - не панацея.
В некоторых случаях вы не обойдетесь без знаний и основного "талмуда".
Подробности и полное техническое описание расписаны в readme.txt

View File

@@ -0,0 +1,122 @@
Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt.
Как обычно, компьютерная грамотность ложится полностью на вас.
Вы должны уметь работать с консолью windows и иметь минимальные навыки обращения с командными файлами bat,cmd.
Если грамотность отсутствует и возникает куча "как" на базовых вещах - проходите мимо или ищите помощь в другом месте.
Обход DPI является хакерской методикой. Под этим словом понимается метод, которому сопротивляется окружающая среда,
которому автоматически не гарантирована работоспособность в любых условиях и на любых ресурсах,
требуется настройка под специфические условия у вашего провайдера. Условия могут меняться со временем,
и методика может начинать или переставать работать, может потребоваться повторный анализ ситуации.
Могут обнаруживаться отдельные ресурсы, которые заблокированы иначе, и которые не работают или перестали работать.
Могут и сломаться отдельные незаблокированные ресурсы.
Поэтому очень желательно иметь знания в области сетей, чтобы иметь возможность проанализировать техническую ситуацию.
Не будет лишним иметь обходные каналы проксирования трафика на случай, если обход DPI не помогает.
Будем считать, что у вас есть windows 7 или выше. Задача - обойти блокировки с самой системы.
Есть решение самое простое, а есть "как положено".
САМОЕ ПРОСТОЕ РЕШЕНИЕ
Совсем ничего не могу, все очень сложно, дайте мне таблетку.
Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip
Запустите zapret-winws/preset_russia.cmd от имени администратора.
Возможно, заведется сразу. Этот вариант похож на "2_any_country.cmd" из GoodbyeDPI.
То же самое с ограничителем по автоматически создаваемому хост-листу preset_russia_autohostlist.cmd.
Что такое autohostlist - читайте readme.txt. Проще говоря, мы обходим только то, что долго и упорно не хочет открываться.
Сначала не будет, но надо пытаться много раз, и тогда сработает, а дальше будет всегда срабатывать.
Остальное не будет ломаться. Использовать только, если первый вариант тоже работает.
Не помогла таблетка ? Это вовсе не значит, что ничего не получится. Но придется делать по-нормальному.
РЕШЕНИЕ "КАК ПОЛОЖЕНО"
1) Если у вас windows 7, обновляйте систему. Годами не обновляемая 7-ка может не запускать драйвер windivert.
Поддержка 32-битных x86 windows возможна, но в готовом виде отсутствует.
На windows 11 arm64 выполните arm64/install_arm64.cmd от имени администратора и перезагрузите компьютер.
Читайте docs/windows.txt
Имейте в виду, что антивирусы могут плохо реагировать на windivert.
cygwin имеет внушительный список несовместимостей с антивирусами. Многие антивирусы его ломают.
https://www.cygwin.com/faq.html#faq.using.bloda
Если это имеет место , используйте исключения. Если это не помогает - отключайте антивирус совсем.
2) Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и сам zapret.
3) Если вы работаете в виртуальной машине, необходимо использовать соединение с сетью в режиме bridge. nat не подходит
4) Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip
5) Запустите blockcheck\blockcheck.cmd. blockcheck в начале проверяет DNS. Если выводятся сообщения о подмене адресов, то
первым делом нужно решить эту проблему, иначе ничего не будет работать.
Решение проблемы DNS выходит за рамки проекта. Обычно она решается либо заменой DNS серверов
от провайдера на публичные (1.1.1.1, 8.8.8.8), либо в случае перехвата провайдером обращений
к сторонним серверам - через специальные средства шифрования DNS запросов, такие как dnscrypt, DoT, DoH.
В современных броузерах чаще всего DoH включен по умолчанию, но curl будет использовать обычный системный DNS.
Новые билды win10 и win11 поддерживают системные DoH из коробки. Они не настроены по умолчанию.
Тут все разжевано как и где это включается : https://hackware.ru/?p=13707
6) blockcheck позволяет выявить рабочую стратегию обхода блокировок.
Лог скрипта будет сохранен в blockcheck\blockcheck.log.
Запомните найденные стратегии.
Следует понимать, что blockcheck проверяет доступность только конкретного домена, который вы вводите в начале.
Вероятно, все остальные домены блокированы подобным образом, но не факт.
В большинстве случаев можно обьединить несколько стратегий в одну универсальную, но для этого необходимо понимать
"что там за буковки". Если вы в сетях слабо разбираетесь, это не для вас. В противном случае читайте readme.txt.
zapret не может пробить блокировку по IP адресу
Для проверки нескольких доменов вводите их через пробел.
Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у вас может быть несколько маршрутов
с различной длиной по ХОПам, с DPI на разных хопах. Приходится преодолевать целый зоопарк DPI,
которые еще и включаются в работу хаотичным образом или образом, зависящим от направления (IP сервера).
blockcheck не всегда может выдать вам в итогах оптимальную стратегию, которую надо просто переписать в настройки.
В некоторых случаях надо реально думать что происходит, анализируя результат на разных стратегиях.
Если вы применяете большой TTL, чтобы достать до магистрала, то не лишним будет добавить дополнительный ограничитель
--dpi-desync-fooling, чтобы не сломать сайты на более коротких дистанциях.
md5sig наиболее совместим, но работатет только на linux серверах.
badseq может работать только на https и не работать на http.
Чтобы выяснить какие дополнительные ограничители работают, смотрите результат теста аналогичных стратегий без TTL
с каждым из этих ограничителей.
При использовании autottl следует протестировать как можно больше разных доменов. Эта техника
может на одних провайдерах работать стабильно, на других потребуется выяснить при каких параметрах
она стабильна, на третьих полный хаос, и проще отказаться.
Если используются методы нулевой фазы десинхронизации (--wssize, --dpi-desync=syndata) и фильтр hostlist,
то все параметры, относящиеся к этим методам, следует помещать в следующий профиль без хостлиста,
к которому перейдет управление, когда имя хоста еще неизвестно.
Используйте параметр --debug для отладки вашего сценария.
7) Протестируйте найденные стратегии на winws. winws следует брать из zapret-winws.
Для этого откройте командную строку windows от имени администратора в директории zapret-winws.
Проще всего это сделать через _CMD_ADMIN.cmd. Он сам поднимет права и зайдет в нужную директорию.
8) Обеспечьте удобную загрузку обхода блокировок.
Есть 2 варианта. Ручной запуск через ярлык или автоматический при старте системы, вне контекста текущего пользователя.
Последний вариант разделяется на запуск через планировщик задач и через службы windows.
Если хотите ручной запуск, скопируйте preset_russia.cmd в preset_my.cmd и адаптируйте его под ваши параметра запуска.
Потом можно создать ярлык на рабочем столе на preset_my.cmd. Не забудьте, что требуется запускать от имени администратора.
Но лучше будет сделать неинтерактивный автоматический запуск вместе с системой.
В zapret-winws есть командные файлы task_*, предназначенные для управления задачами планировщика.
Там следует поменять содержимое переменной WINWS1 на свою стратегию.
Если вы не можете обьединить несколько стратегий для разных протоколов в одну, дублируйте код в каждом из cmd
для поддержки нескольких задач : winws1,winws2,winws3.
После создания задач запустите их. Проверьте, что обход встает после перезагрузки windows.
Аналогично настраиваются и службы windows. Смотрите service_*.cmd
9) Если ломаются отдельные незаблокированные ресурсы, используйте хост-листы.
Где они будут находиться - решайте сами.
Параметры управления хост-листами точно такие же, как в *nix.
Это минимальная инструкция, чтобы соориентироваться с чего начать. Однако, это - не панацея.
В некоторых случаях вы не обойдетесь без знаний и основного "толмуда".
Подробности и полное техническое описание расписаны в readme.txt

1272
docs/readme.eng.md Normal file

File diff suppressed because it is too large Load Diff

1937
docs/readme.txt Normal file

File diff suppressed because it is too large Load Diff

196
docs/redsocks.txt Normal file
View File

@@ -0,0 +1,196 @@
Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему.
Если вы не знаете основ сетей, linux, openwrt, а пытаетесь что-то скопипастить отсюда без малейшего
понимания смысла, то маловероятно, что у вас что-то заработает. Не тратье свое время напрасно.
Цель - донести принципы как это настраивается вообще, а не указать какую буковку где вписать.
Прозрачный выборочный заворот tcp соединений на роутере через socks
Tor поддерживает "из коробки" режим transparent proxy. Это можно использовать в теории, но практически - только на роутерах с 128 мб памяти и выше. И тор еще и тормозной.
Другой вариант напрашивается, если у вас есть доступ к какой-нибудь unix системе с SSH, где сайты не блокируются. Например, у вас есть VPS вне России.
Понятийно требуются следующие шаги :
1) Выделять IP, на которые надо проксировать трафик. У нас уже имеется ipset "zapret", технология создания которого отработана.
2) Сделать так, чтобы все время при загрузке системы на некотором порту возникал socks.
3) Установить transparent соксификатор. Redsocks прекрасно подошел на эту роль.
4) Завернуть через iptables или nftables трафик с порта назначения 443 и на ip адреса из ipset/nfset 'zapret' на соксификатор
Тоже самое сделать с ipset/nfset 'ipban' для всех tcp портов.
Буду рассматривать систему на базе openwrt, где уже установлена система обхода dpi "zapret".
Если вам не нужны функции обхода DPI, можно выбрать режим MODE=filter.
* Сделать так, чтобы все время при загрузке системы на некотором порту возникал socks
Т.к. дефолтный dropbear клиент не поддерживает создание socks, то для начала придется заменить dropbear ssh client на openssh : пакеты openssh-client и openssh-client-utils.
Устанавливать их нужно с опцией opkg --force-overwrite, поскольку они перепишут ssh клиент от dropbear.
После установки пакетов расслабим неоправданно жестокие права : chmod 755 /etc/ssh.
Следует создать пользователя, под которым будем крутить ssh client. Допустим, это будет 'proxy'.
Сначала установить пакет shadow-useradd.
------------------
useradd -d /home/proxy proxy
mkdir -p /home/proxy
chown proxy:proxy /home/proxy
------------------
Openssh ловит разные глюки, если у него нет доступа к /dev/tty.
Добавим в /etc/rc.local строчку : "chmod 666 /dev/tty"
Сгенерируем для него ключ RSA для доступа к ssh серверу.
------------------
su proxy
cd
mkdir -m 700 .ssh
cd .ssh
ssh-keygen
ls
exit
------------------
Должны получиться файлы id_rsa и id_rsa.pub.
Строчку из id_rsa.pub следует добавить на ssh сервер в файл $HOME/.ssh/authorized_keys.
Более подробно о доступе к ssh через авторизацию по ключам : https://beget.com/ru/articles/ssh_by_key
Предположим, ваш ssh сервер - vps.mydomain.com, пользователь называется 'proxy'.
Проверить подключение можно так : ssh -N -D 1098 -l proxy vps.mydomain.com.
Сделайте это под пользователем "proxy", поскольку при первом подключении ssh спросит о правильности hostkey.
Соединение может отвалиться в любой момент, поэтому нужно зациклить запуск ssh.
Для этого лучший вариант - использовать procd - упрощенная замена systemd на openwrt версий BB и выше.
--- /etc/init.d/socks_vps ---
#!/bin/sh /etc/rc.common
START=50
STOP=50
USE_PROCD=1
USERNAME=proxy
COMMAND="ssh -N -D 1098 -l proxy vps.mydomain.com"
start_service() {
procd_open_instance
procd_set_param user $USERNAME
procd_set_param respawn 10 10 0
procd_set_param command $COMMAND
procd_close_instance
}
-----------------------------
Этому файлу нужно дать права : chmod +x /etc/init.d/socks_vps
Запуск : /etc/init.d/socks_vps start
Останов : /etc/init.d/socks_vps stop
Включить автозагрузку : /etc/init.d/socks_vps enable
Проверка : curl -4 --socks5 127.0.0.1:1098 https://rutracker.org
* Организовать прозрачную соксификацию
Установить пакет redsocks.
Конфиг :
-- /etc/redsocks.conf : ---
base {
log_debug = off;
log_info = on;
log = "syslog:local7";
daemon = on;
user = nobody;
group = nogroup;
redirector = iptables;
}
redsocks {
local_ip = 127.0.0.127;
local_port = 1099;
ip = 127.0.0.1;
port = 1098;
type = socks5;
}
---------------------------
После чего перезапускаем : /etc/init.d/redsocks restart
Смотрим появился ли листенер : netstat -tnlp | grep 1099
В zapret для перенаправления DNAT на интерфейс lo используется 127.0.0.127.
Ко всем остальным адресам из 127.0.0.0/8 DNAT может быть заблокирован. Читайте readme.txt про route_localnet.
* Завертывание соединений через iptables
!! Версии OpenWRT до 21.02 включительно используют iptables + fw3. Более новые перешили на nftables по умолчанию.
!! В новых OpenWRT можно снести firewall4 и nftables, заменив их на firewall3 + iptables
!! Инструкция относится только к openwrt, где используется iptables.
Будем завертывать любые tcp соединения на ip из ipset "ipban" и https на ip из ipset "zapret", за исключением ip из ipset "nozapret".
--- /etc/firewall.user -----
SOXIFIER_PORT=1099
. /opt/zapret/init.d/openwrt/functions
create_ipset no-update
network_find_wan4_all wan_iface
for ext_iface in $wan_iface; do
network_get_device ext_device $ext_iface
ipt OUTPUT -t nat -o $ext_device -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret dst -j REDIRECT --to-port $SOXIFIER_PORT
ipt OUTPUT -t nat -o $ext_device -p tcp -m set --match-set ipban dst -m set ! --match-set nozapret dst -j REDIRECT --to-port $SOXIFIER_PORT
done
prepare_route_localnet
ipt prerouting_lan_rule -t nat -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret -j DNAT --to $TPWS_LOCALHOST4:$SOXIFIER_PORT
ipt prerouting_lan_rule -t nat -p tcp -m set --match-set ipban dst -m set ! --match-set nozapret -j DNAT --to $TPWS_LOCALHOST4:$SOXIFIER_PORT
----------------------------
Внести параметр "reload" в указанное место :
--- /etc/config/firewall ---
config include
option path '/etc/firewall.user'
option reload '1'
----------------------------
Перезапуск firewall : /etc/init.d/firewall restart
* Завертывание соединений через nftables
!! Только для версий OpenWRT старше 21.02
nftables не могут использовать ipset. Вместо ipset существует аналог - nfset.
nfset является частью таблицы nftable и принадлежит только к ней. Адресация nfset из другой nftable невозможна.
Скрипты ipset/* в случае nftables используют nfset-ы в таблице zapret.
Чтобы использовать эти nfset-ы в своих правилах, необходимо синхронизироваться с их созданием и вносить свои цепочки в nftable "zapret".
Для этого существуют хуки - скрипты, вызываемые из zapret на определенных стадиях инициализации фаервола.
Раскоментируейте в /opt/zapret/config строчку
INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up"
Создайте файл /etc/firewall.zapret.hook.post_up и присвойте ему chmod 755.
--- /etc/firewall.zapret.hook.post_up ---
#!/bin/sh
SOXIFIER_PORT=1099
. /opt/zapret/init.d/openwrt/functions
cat << EOF | nft -f - 2>/dev/null
delete chain inet $ZAPRET_NFT_TABLE my_output
delete chain inet $ZAPRET_NFT_TABLE my_prerouting
EOF
prepare_route_localnet
cat << EOF | nft -f -
add chain inet $ZAPRET_NFT_TABLE my_output { type nat hook output priority -102; }
flush chain inet $ZAPRET_NFT_TABLE my_output
add rule inet $ZAPRET_NFT_TABLE my_output oifname @wanif meta l4proto tcp ip daddr @ipban ip daddr != @nozapret dnat to $TPWS_LOCALHOST4:$SOXIFIER_PORT
add rule inet $ZAPRET_NFT_TABLE my_output oifname @wanif tcp dport 443 ip daddr @zapret ip daddr != @nozapret dnat to $TPWS_LOCALHOST4:$SOXIFIER_PORT
add chain inet $ZAPRET_NFT_TABLE my_prerouting { type nat hook prerouting priority -102; }
flush chain inet $ZAPRET_NFT_TABLE my_prerouting
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname @lanif meta l4proto tcp ip daddr @ipban ip daddr != @nozapret dnat to $TPWS_LOCALHOST4:$SOXIFIER_PORT
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname @lanif tcp dport 443 ip daddr @zapret ip daddr != @nozapret dnat to $TPWS_LOCALHOST4:$SOXIFIER_PORT
EOF
----------------------------
Перезапуск firewall : /etc/init.d/zapret restart_fw
* Проверка
Все, теперь можно проверять :
/etc/init.d/redsocks stop
curl -4 https://rutracker.org
# должно обломаться с надписью "Connection refused". если не обламывается - значит ip адрес rutracker.org не в ipset,
# либо не сработали правила фаервола. например, из-за не установленных модулей ipt
/etc/init.d/redsocks start
curl -4 https://rutracker.org
# должно выдать страницу

161
docs/windows.eng.md Normal file
View File

@@ -0,0 +1,161 @@
### tpws
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 -d tpws --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 <fooling_options>`
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).
`--oob` , `--mss` and `--disorder` do not work.
RST detection in autohostlist scheme may not work.
WSL may glitch with splice. `--nosplice` may be required.
### winws
`winws` is `nfqws` version for windows. It's based on `windivert`. Most functions are working.
Large ip filters (ipsets) are not possible. Forwarded traffic and connection sharing are not supported.
Administrator rights are required.
Working with packet filter consists of two parts
1. In-kernel packet selection and passing selected packets to a packet filter in user mode.
In *nix it's done by `iptables`, `nftables`, `pf`, `ipfw`.
2. User mode packet filter processes packets and does DPI bypass magic.
Windows does not have part 1. No `iptables` exist. That's why 3rd party packet redirector is used.
It's called `windivert`. It works starting from `windows 7`. Kernel driver is signed but it may require to disable secure boot
or update windows 7. Read below for windows 7 windivert signing info.
Task of `iptables` is done inside `winws` through `windivert` filters. `Windivert` has it's own [filter language](https://reqrypt.org/windivert-doc.html#filter_language).
`winws` can automate filter construction using simple ip version and port filter. Raw filters are also supported.
```
--wf-iface=<int>[:<int>] ; numeric network interface and subinterface indexes
--wf-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--wf-tcp=[~]port1[-port2] ; TCP port filter. ~ means negation. multiple comma separated values allowed.
--wf-udp=[~]port1[-port2] ; UDP port filter. ~ means negation. multiple comma separated values allowed.
--wf-raw=<filter>|@<filename> ; raw windivert filter string or filename
--wf-save=<filename> ; save windivert filter string to a file and exit
--ssid-filter=ssid1[,ssid2,ssid3,...] ; enable winws only if any of specified wifi SSIDs connected
--nlm-filter=net1[,net2,net3,...] ; enable winws only if any of specified NLM network is connected. names and GUIDs are accepted.
--nlm-list[=all] ; list Network List Manager (NLM) networks. connected only or all.
```
`--wf-l3`, `--wf-tcp`, `--wf-udp` can take multiple comma separated arguments.
Interface indexes can be discovered using this command : `netsh int ip show int`
If you can't find index this way use `winws --debug` to see index there. Subinterface index is almost always 0 and you can omit it.
Multiple `winws` processes are allowed. However, it's discouraged to intersect their filters.
`--ssid-filter` allows to enable `winws` only if specified wifi networks are connected. `winws` auto detects SSID appearance and disappearance.
SSID names must be written in the same case as the system sees them. This option does not analyze routing and does not detect where traffic actually goes.
If multiple connections are available, the only thing that triggers `winws` operation is wifi connection presence. That's why it's a good idea to add also `--wf-iface` filter to not break ethernet, for example.
`--nlm-filter` is like `--ssid-filter` but works with names or GUIDs from Network List Manager. NLM names are those you see in Control Panel "Network and Sharing Center".
NLM networks are adapter independent. Usually MAC address of the default router is used to distinugish networks. NLM works with any type of adapters : ethernet, wifi, vpn and others.
That's why NLM is more universal than `ssid-filter`.
`Cygwin` shell does not run binaries if their directory has it's own copy of `cygwin1.dll`.
That's why exists separate standalone version in `binaries/win64/zapret-tpws`.
`Cygwin` is required for `blockcheck.sh` support but `winws` itself can be run standalone without cygwin.
How to get `windows 7` and `winws` compatible `cygwin` :
```
curl -O https://www.cygwin.com/setup-x86_64.exe
setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215
```
You must choose to install `curl`. To compile from sources install `gcc-core`,`make`,`zlib-devel`.
`winws` requires `cygwin1.dll`, `windivert.dll`, `windivert64.sys`. You can take them from `binaries/win64/zapret-winws`.
It's possible to build x86 32-bit version but this version is not shipped. You have to build it yourself.
32-bit `windivert` can be downloaded from it's developer github. Required version is 2.2.2.
There's no `arm64` signed `windivert` driver and no `cygwin`.
But it's possible to use unsigned driver version in test mode and user mode components with x64 emulation.
x64 emulation requires `windows 11` and not supported in `windows 10`.
### windows 7 windivert signing
Requirements for windows driver signing have changed in 2021.
Official free updates of windows 7 ended in 2020.
After 2020 for the years paid updates were available (ESU).
One of the updates from ESU enables signatures used in windivert 2.2.2-A.
There are several options :
1. Take `windivert64.sys` and `windivert.dll` version `2.2.0-C` or `2.2.0-D` from [here](https://reqrypt.org/download).
Replace these 2 files in every location they are present.
In `zapret-win-bundle` they are in `zapret-winws` и `blockcheck/zapret/nfq` folders.
However this option still requires 10+ year old patch that enables SHA256 signatures.
2. [Hack ESU](https://hackandpwn.com/windows-7-esu-patching)
3. Use `UpdatePack7R2` from simplix : https://blog.simplix.info
If you are in Russia or Belarus temporary change region in Control Panel.
### blockcheck
`blockcheck.sh` is written in posix shell and uses some standard posix utilites.
Windows does not have them. To execute `blockcheck.sh` use `cygwin` command prompt run as administrator.
It's not possible to use `WSL`. It's not the same as `cygwin`.
First run once `install_bin.sh` then `blockcheck.sh`.
Backslashes in windows paths shoud be doubled. Or use cygwin path notation.
```
cd "C:\\Users\\vasya"
cd "C:/Users/vasya"
cd "/cygdrive/c/Users/vasya"
```
`Cygwin` is required only for `blockcheck.sh`. Standalone `winws` can be run without it.
### auto start
To start `winws` with windows use windows task scheduler. There are `task_*.cmd` batch files in `binaries/win64/zapret-winws`.
They create, remove, start and stop scheduled task `winws1`. They must be run as administrator.
Edit `task_create.cmd` and write your `winws` parameters to `%WINWS1%` variable. If you need multiple `winws` instances
clone the code in all cmd files to support multiple tasks `winws1,winws2,winws3,...`.
Tasks can also be controlled from GUI `taskschd.msc`.
Also you can use windows services the same way with `service_*.cmd`.
### zapret-win-bundle
To make your life easier there's ready to use [bundle](https://github.com/bol-van/zapret-win-bundle) with `cygwin`,`blockcheck` and `winws`.
* `/zapret-winws` - standalone version of `winws` for everyday use. does not require any other folders.
* `/zapret-winws/_CMD_ADMIN.cmd` - open `cmd` as administrator in the current folder
* `/blockcheck/blockcheck.cmd` - run `blockcheck` with logging to `blockcheck/blockcheck.log`
* `/cygwin/cygwin.cmd` - run `cygwin` shell as current user
* `/cygwin/cygwin-admin.cmd` - run `cygwin` shell as administrator
There're aliases in cygwin shell for `winws`,`blockcheck`,`ip2net`,`mdig`. No need to mess with paths.
It's possible to send signals to `winws` using standard unix utilites : `pidof,kill,killall,pgrep,pkill`.
`Cygwin` shares common process list per `cygwin1.dll` copy. If you run a `winws` from `zapret-winws`
you won't be able to `kill` it because this folder contain its own copy of `cygwin1.dll`.
It's possible to use `cygwin` shell to make `winws` debug log. Use `tee` command like this :
```
winws --debug --wf-tcp=80,443 | tee winws.log
unix2dos winws.log
```
`winws.log` will be in `cygwin/home/<username>`. `unix2dos` helps with `windows 7` notepad. It's not necessary in `Windows 10` and later.

222
docs/windows.txt Normal file
View File

@@ -0,0 +1,222 @@
tpws
----
Запуск tpws возможен только в Linux варианте под WSL.
Нативного варианта под Windows нет, поскольку он использует epoll, которого под windows не существует.
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 -d tpws --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).
Не работают функции --oob и --mss из-за ограничений реализации WSL.
--disorder не работает из-за особенностей tcp/ip стека windows.
Может не срабатывать детект RST в autohostlist.
WSL может глючить со splice, приводя к зацикливанию процесса. Может потребоваться --nosplice.
Не поддерживается tcp user timeout.
Чтобы избавиться от исообщений об ошибке добавляйте "--local-tcp-user-timeout=0 --remote-tcp-user-timeout=0".
Эти сообщения только информативные, на работу они не влияют.
winws
-----
Это вариант пакетного фильтра nfqws для Windows, построенный на базе windivert.
Все функции работоспособны, однако функционал ipset отсутствует. Фильтры по большому количеству IP адресов невозможны.
Работа с проходящим трафиком, например в случае "расшаривания" соединения, не проверялась и не гарантируется.
Для работы с windivert требуются права администратора.
Специфические для unix параметры, такие как --uid, --user и тд, исключены. Все остальные параметры аналогичны nfqws и dvtws.
Работа с пакетным фильтром основана на двух действиях.
Первое - выделение перенаправляемого трафика в режиме ядра и передача его пакетному фильтру в user mode.
Второе - собственно обработка перенаправленных пакетов в пакетном фильтре.
В windows отсутствуют встроенные средства для перенаправления трафика, такие как iptables, nftables, pf или ipfw.
Поэтому используется сторонний драйвер ядра windivert. Он работает, начиная с windows 7. На системах с включенным
secure boot могут быть проблемы из-за подписи драйвера. В этом случае отключите secureboot или включите режим testsigning.
На windows 7 вероятно будут проблемы с загрузкой windivert. Читайте ниже соответствующий раздел.
Задача iptables в winws решается внутренними средствами через фильтры windivert.
У windivert существует собственный язык фильтров, похожий на язык фильтров wireshark.
Документация по фильтрам windivert : https://reqrypt.org/windivert-doc.html#filter_language
Чтобы не писать сложные фильтры вручную, предусмотрены различные упрощенные варианты автоматического построения фильтров.
--wf-iface=<int>[.<int>] ; числовые индексы интерфейса и суб-интерфейса
--wf-l3=ipv4|ipv6 ; фильтр L3 протоколов. по умолчанию включены ipv4 и ipv6.
--wf-tcp=[~]port1[-port2] ; фильтр портов для tcp. ~ означает отрицание
--wf-udp=[~]port1[-port2] ; фильтр портов для udp. ~ означает отрицание
--wf-raw=<filter>|@<filename> ; задать напрямую фильтр windivert из параметра или из файла. имени файла предшествует символ @.
--wf-save=<filename> ; сохранить сконструированный фильтр windivert в файл для последующей правки вручную
--ssid-filter=ssid1[,ssid2,ssid3,...] ; включать winws только когда подключена любая из указанных wifi сетей
--nlm-filter=net1[,net2,net3,...] ; включать winws только когда подключена любая из указанных сетей NLM
--nlm-list[=all] ; вывести список сетей NLM. по умолчанию только подключенных, all - всех.
Параметры --wf-l3, --wf-tcp, --wf-udp могут брать несколько значений через запятую.
Номера интерфейсов можно узнать так : netsh int ip show int.
Некоторых типы соединений там не увидеть. В этом случае запускайте winws с параметром --debug и смотрите IfIdx там.
SubInterface используется windivert, но практически всегда 0, его можно не указывать. Вероятно он нужен в редких случаях.
Конструктор фильтров автоматически включает входящие tcp пакеты с tcp synack и tcp rst для корректной работы функций
autottl и autohostlist. При включении autohostlist так же перенаправляются пакеты данных с http redirect с кодами 302 и 307.
Всегда добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6.
Для сложных нестандартных сценариев могут потребоваться свои фильтры. Логично будет начать со стандартного шаблона,
сохраненного через --wf-save. Нужно править файл и подсовывать его в параметре --wf-raw. Максимальный размер фильтра - 8 Kb.
Можно запускать несколько процессов winws с разными стратегиями. Однако, не следует делать пересекающиеся фильтры.
В --ssid-filter можно через запятую задать неограниченное количество имен wifi сетей (SSID). Если задана хотя бы одна сеть,
то winws включается только, если подключен указанный SSID. Если SSID исчезает, winws отключается. Если SSID появляется снова,
winws включается. Это нужно, чтобы можно было применять раздельное дурение к каждой отдельной wifi сети.
Названия сетей должны быть написаны в том регистре, в котором их видит система. Сравнение идет с учетом регистра !
При этом нет никаких проверок куда реально идет трафик. Если одновременно подключен, допустим, ethernet,
и трафик идет туда, то дурение включается и выключается просто по факту наличия wifi сети, на которую трафик может и не идти.
И это может сломать дурение на ethernet. Поэтому полезно так же будет добавить фильтр --wf-iface на индекс интерфейса wifi адаптера,
чтобы не трогать другой трафик.
--nlm-filter аналогичен --ssid-filter, но работает с именами или GUIDами сетей Network List Manager (NLM).
Это те сети, которые вы видите в панели управления в разделе "Центр управления сетями и общим доступом".
Под сетью подразумевается не конкретный адаптер, а именно сетевое окружение конкретного подключения.
Обычно проверяется mac адрес шлюза. К сети можно подключиться через любой адаптер, и она останется той же самой.
Если подключиться, допустим, к разными роутерам по кабелю, то будут разные сети.
А если к одному роутеру через 2 разных сетевых карточки на том же компе - будет одна сеть.
NLM абстрагирует типы сетевых адаптеров. Он работает как с wifi, так и с ethernet и любыми другими.
Поэтому это более универсальный метод, чем ssid фильтр.
Однако, есть и неприятная сторона. В windows 7 вы легко могли ткнуть на иконку сети и выбрать тип : private или public.
Там же вы могли посмотреть список сетей и обьединить их. Чтобы, допустим, вы могли подключаться по кабелю и wifi
к одному роутеру, и система эти подключения воспринимала как одну сеть.
В следующих версиях windows они эти возможности сильно порезали. Похоже нет встроенных средств полноценно управлять
network locations в win10/11. Кое-что есть в powershell.
Можно поковыряться напрямую в реестре здесь : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList
Нужно менять ProfileGUID в Signatures\Unmanaged. Имена можно поменять в Profiles.
Есть кое-какие сторонние утилиты. Кое-что находится, позволяющее посмотреть и удалить network profiles, но не обьединить.
Факт, что в ms они это сильно испортили. Движок network list все тот же, и он способен на все то, что было в win7.
Можно не бороться с этой проблемой, а просто указывать через запятую те названия сетей или GUIDы, которые выбрала система.
Или если у вас только wifi, то использовать --ssid-filter. Там хотя бы есть гарантия, что SSID соответствуют реальности,
а система их не назвала как-то по-своему.
Если в путях присутствуют национальные символы, то при вызове winws из cmd или bat кодировку нужно использовать OEM.
Для русского языка это 866. Пути с пробелами нужно брать в кавычки.
Существует неочевидный момент, каcаемый запуска winws из cygwin шелла. Если в директории, где находится nfqws, находится
копия cygwin1.dll, winws не запустится. Поэтому в binaries/win64 существует директория zapret-winws, содержащая полный
комплект для запуска без cygwin. Его вы и берете для повседневного использования.
Если нужен запуск под cygwin, то следует запускать из binaries/win64. Это нужно для работы blockcheck.
Из cygwin шелла можно посылать winws сигналы через kill точно так же, как в *nix.
Как получить совместимый с windows 7 и winws cygwin :
curl -O https://www.cygwin.com/setup-x86_64.exe
setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215
Следует выбрать установку curl.
Для сборки из исходников требуется gcc-core,make,zlib-devel.
Собирать из директории nfq командой "make cygwin".
winws требует cygwin1.dll, windivert.dll, windivert64.sys. Их можно взять из binaries/win64/zapret-winws.
Версию для 32-битных x86 windows собрать можно, но такие системы уже уходят в прошлое, поэтому если надо - собирайте сами.
32-битный windivert можно взять с сайта разработчика. Требуется версия 2.2.2.
Для arm64 windows нет подписанного драйвера windivert и нет cygwin.
Однако, эмуляция x64 windows 11 позволяет использовать все, кроме WinDivert64.sys без изменений.
Но при этом надо заменить WinDivert64.sys на неподписанную arm64 версию и установить режим testsigning.
Windows 7 и windivert
---------------------
Требования к подписи драйверов windows изменились в 2021 году.
Официальные бесплатные обновления windows 7 закончились в 2020.
После этого несколько лет продолжали идти платные обновления по программе ESU.
Именно в этих ESU обновлениях находится обновление ядра windows 7, позволяющиее загрузить драйвер
windivert 2.2.2-A, который идет в поставке zapret.
Поэтому варианты следующие :
1) Взять windivert64.sys и windivert.dll версии 2.2.0-C или 2.2.0-D отсюда : https://reqrypt.org/download
и заменить эти 2 файла.
В zapret-win-bundle есть отдельных 2 места, где находится winws : zapret-winws и blockcheck/zapret/nfq.
Надо менять в обоих местах.
Этот вариант проверен и должен работать. Тем не менее патч 10 летней давности, который включает SHA256
сигнатуры, все еще необходим.
2) Взломать ESU :
https://hackandpwn.com/windows-7-esu-patching/
http://www.bifido.net/tweaks-and-scripts/8-extended-security-updates-installer.html
и обновить систему
3) Использовать UpdatePack7R2 от simplix : https://blog.simplix.info
Но с этим паком есть проблема. Автор из Украины, он очень обиделся на русских.
Если в панели управления стоит регион RU или BY, появляется неприятный диалог.
Чтобы эту проблему обойти, можно поставить временно любой другой регион, потом вернуть.
Так же нет никаких гарантий, что автор не насовал туда какой-то зловредный код.
Использовать на свой страх и риск.
Более безопасный вариант - скачать последнюю нормальную довоенную версию : 22.2.10
https://nnmclub.to/forum/viewtopic.php?t=1530323
Ее достаточно, чтобы windivert 2.2.2-A заработал на windows 7.
blockcheck
----------
blockcheck.sh написан на posix shell и требует некоторых стандартных утилит posix. В windows, естественно, этого нет.
Потому просто так запустить blockcheck.sh невозможно.
Для этого требуется скачать и установить cygwin так , как описано в предыдущем разделе.
Следует запустить от имени администратора cygwin shell через cygwin.bat.
В нем нужно пройти в директорию с zapret.
Обратные слэши путей windows нужно удваивать, менять на прямые слэши, либо использовать отображение на unix path.
Корректный вариант 1 : cd "C:\\Users\\vasya"
Корректный вариант 2 : cd "C:/Users/vasya"
Корректный вариант 3 : cd "/cygdrive/c/Users/vasya"
Далее все как в *nix : 1 раз ./install_bin.sh , затем ./blockcheck.sh.
WSL использовать нельзя, это не то же самое.
cygwin для обычной работы winws не нужен. Разве что вы хотите посылать winws SIGHUP для перечитки листов без перезапуска.
автозапуск winws
----------------
Для запуска winws вместе с windows есть 2 варианта. Планировщик задач или службы windows.
Можно создавать задачи и управлять ими через консольную программу schtasks.
В директории binaries/win64/winws подготовлены файлы task_*.cmd .
В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной %WINWS1%.
Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код
для задач winws1,winws2,winws3,...
Аналогично настраивается вариант запуска через службы windows. Смотрите service_*.cmd.
Все батники требуется запускать от имени администратора.
Управлять задачами можно так же из графической программы управления планировщиком taskschd.msc
zapret-win-bundle
-----------------
Можно не возиться с cygwin, а взять готовый пакет, включающий в себя cygwin и blockcheck : https://github.com/bol-van/zapret-win-bundle
Там сделан максимум удобств для сосредоточения на самом zapret, исключая возню с установкой cygwin,
заходами в директории, запусками под администратором и прочими сугубо техническими моментами, в которых могут быть
ошибки и непонимания, а новичок без базиса знаний может и вовсе запутаться.
/zapret-winws - здесь все, что нужно для запуска winws в повседневном рабочем режиме. остальное не нужно.
/zapret-winws/_CMD_ADMIN.cmd - получить командную строку cmd в этой директории от имени администратора для тестирования winws
с параметрами, вводимыми вручную
/blockcheck/blockcheck.cmd - достаточно кликнуть по нему, чтобы пошел blockcheck с записью лога в blockcheck/blockcheck.log
/cygwin/cygwin.cmd - запуск среды cygwin bash под текущим пользователем
/cygwin/cygwin-admin.cmd - запуск среды cygwin bash под администратором
В среде cygwin уже настроены alias-ы на winws,blockcheck,ip2net,mdig. С путями возиться не нужно !
Из cygwin можно не только тестировать winws, но и посылать сигналы.
Доступны команды pidof,kill,killall,pgrep,pkill.
Но важно понимать, что таким образом не выйдет посылать сигналы winws, запущенному из zapret-winws,
поскольку там свой cygwin1.dll, и они не разделяют общее пространство процессов unix.
zapret-winws - это отдельный комплект для повседневного использования, не требующий что-то еще, но и не связанный со средой cygwin.
Среду cygwin можно использовать для записи в файл дебаг-лога winws. Для этого пользуйтесь командой tee.
winws --debug --wf-tcp=80,443 | tee winws.log
winws.log будет в cygwin/home/<имя_пользователя>
Если у вас windows 7, то блокнот не поймет переводы строк в стиле unix. Воспользуйтесь командой
unix2dos winws.log

View File

@@ -0,0 +1,133 @@
Index: WireGuard-0.0.20190123/src/cookie.c
===================================================================
--- WireGuard-0.0.20190123.orig/src/cookie.c
+++ WireGuard-0.0.20190123/src/cookie.c
@@ -193,6 +193,8 @@ void wg_cookie_message_create(struct mes
xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN,
macs->mac1, COOKIE_LEN, dst->nonce,
checker->cookie_encryption_key);
+ // MOD : randomize trash
+ dst->header.trash = gen_trash();
}
void wg_cookie_message_consume(struct message_handshake_cookie *src,
Index: WireGuard-0.0.20190123/src/messages.h
===================================================================
--- WireGuard-0.0.20190123.orig/src/messages.h
+++ WireGuard-0.0.20190123/src/messages.h
@@ -53,23 +53,41 @@ enum limits {
MAX_QUEUED_PACKETS = 1024 /* TODO: replace this with DQL */
};
+/*
enum message_type {
- MESSAGE_INVALID = 0,
- MESSAGE_HANDSHAKE_INITIATION = 1,
- MESSAGE_HANDSHAKE_RESPONSE = 2,
- MESSAGE_HANDSHAKE_COOKIE = 3,
- MESSAGE_DATA = 4
+ MESSAGE_INVALID = 0,
+ MESSAGE_HANDSHAKE_INITIATION = 1,
+ MESSAGE_HANDSHAKE_RESPONSE = 2,
+ MESSAGE_HANDSHAKE_COOKIE = 3,
+ MESSAGE_DATA = 4
};
+*/
+
+// MOD : message type
+enum message_type {
+ MESSAGE_INVALID = 0xE319CCD0,
+ MESSAGE_HANDSHAKE_INITIATION = 0x48ADE198,
+ MESSAGE_HANDSHAKE_RESPONSE = 0xFCA6A8F3,
+ MESSAGE_HANDSHAKE_COOKIE = 0x64A3BB18,
+ MESSAGE_DATA = 0x391820AA
+};
+
+// MOD : generate fast trash without true RNG
+__le32 gen_trash(void);
struct message_header {
- /* The actual layout of this that we want is:
- * u8 type
- * u8 reserved_zero[3]
- *
- * But it turns out that by encoding this as little endian,
- * we achieve the same thing, and it makes checking faster.
- */
- __le32 type;
+ /* The actual layout of this that we want is:
+ * u8 type
+ * u8 reserved_zero[3]
+ *
+ * But it turns out that by encoding this as little endian,
+ * we achieve the same thing, and it makes checking faster.
+ */
+
+ // MOD : trash field to change message size and add 4 byte offset to all fields
+ __le32 trash;
+
+ __le32 type;
};
struct message_macs {
Index: WireGuard-0.0.20190123/src/noise.c
===================================================================
--- WireGuard-0.0.20190123.orig/src/noise.c
+++ WireGuard-0.0.20190123/src/noise.c
@@ -17,6 +17,24 @@
#include <linux/highmem.h>
#include <crypto/algapi.h>
+
+// MOD : trash generator
+__le32 gtrash = 0;
+__le32 gen_trash(void)
+{
+ if (gtrash)
+ gtrash = gtrash*1103515243 + 12345;
+ else
+ // first value is true random
+ get_random_bytes_wait(&gtrash, sizeof(gtrash));
+ return gtrash;
+}
+
/* This implements Noise_IKpsk2:
*
* <- s
@@ -515,6 +533,10 @@ wg_noise_handshake_create_initiation(str
&handshake->entry);
handshake->state = HANDSHAKE_CREATED_INITIATION;
+
+ // MOD : randomize trash
+ dst->header.trash = gen_trash();
+
ret = true;
out:
@@ -655,6 +677,10 @@ bool wg_noise_handshake_create_response(
&handshake->entry);
handshake->state = HANDSHAKE_CREATED_RESPONSE;
+
+ // MOD : randomize trash
+ dst->header.trash = gen_trash();
+
ret = true;
out:
Index: WireGuard-0.0.20190123/src/send.c
===================================================================
--- WireGuard-0.0.20190123.orig/src/send.c
+++ WireGuard-0.0.20190123/src/send.c
@@ -200,6 +200,10 @@ static bool encrypt_packet(struct sk_buf
header->header.type = cpu_to_le32(MESSAGE_DATA);
header->key_idx = keypair->remote_index;
header->counter = cpu_to_le64(PACKET_CB(skb)->nonce);
+
+ // MOD : randomize trash
+ header->header.trash = gen_trash();
+
pskb_put(skb, trailer, trailer_len);
/* Now we can encrypt the scattergather segments */

View File

@@ -0,0 +1,250 @@
!!! Эта инструкция написана еще до включения wireguard в ядро linux.
!!! Процесс сборки для in-tree модулей отличается.
!!! Цель данного чтива - дать идею для программистов как можно исправить исходники wireguard
!!! для преодоления DPI. Автор не преследует цели поддерживать готовые патчи для актуальных версий.
!!! Вместо патчинга гораздо проще использовать навесное решение ipobfs.
Посвящено возможной блокировке в РФ VPN протоколов через DPI.
Предпосылками являются последние законодательные акты и во всю сочащиеся "секретные" записки.
В РФ разрабатываются и готовятся к применению более продвинутые решения по блокировке трафика.
Вполне вероятно будут резать стандартные VPN протоколы. Нам надо быть к этому готовыми.
Один из возможных и перспективных путей решения данного вопроса - кустомная модификация
исходников VPN с целью незначительного изменения протокола, ломающего стандартные модули обнаружения в DPI.
Это относительно сложно, доступно только для гиков.
Никто не будет разрабатывать специальные модули обнаружения в DPI, если только кто-то не сделает простое и
удобное решение для всех, и его станут широко применять. Но это маловероятно, и даже если и так,
то всегда можно модифицировать протокол чуток по другому. Делать моды для DPI несравненно дольше
и дороже, чем клепать на коленке изменения протокола для wireguard.
ЗАМЕЧЕНИЕ : альтернативой модификации конечного софта для VPN является использование "навесных"
обфускаторов. см : https://github.com/bol-van/ipobfs
Рассмотрю что нам надо пропатчить в wireguard. Модифицированный wireguard проверен на виртуалках
с десктопным linux, он работает, сообщения в wireshark действительно не вписываются в стандартный
протокол и не опознаются.
Wireguard протокол очень простой. Все сообщения описаны в messages.h
Поставим себе целью сделать 2 простые модификации :
1) Добавим в начало всех сообщений немного мусора, чтобы изменить размер сообщений и смещения полей
2) Изменим коды типов сообщений
Этого может быть вполне достаточно для обмана DPI
--messages.h--------------------------
/*
enum message_type {
MESSAGE_INVALID = 0,
MESSAGE_HANDSHAKE_INITIATION = 1,
MESSAGE_HANDSHAKE_RESPONSE = 2,
MESSAGE_HANDSHAKE_COOKIE = 3,
MESSAGE_DATA = 4
};
*/
// MOD : message type
enum message_type {
MESSAGE_INVALID = 0xE319CCD0,
MESSAGE_HANDSHAKE_INITIATION = 0x48ADE198,
MESSAGE_HANDSHAKE_RESPONSE = 0xFCA6A8F3,
MESSAGE_HANDSHAKE_COOKIE = 0x64A3BB18,
MESSAGE_DATA = 0x391820AA
};
// MOD : generate fast trash without true RNG
__le32 gen_trash(void);
struct message_header {
/* The actual layout of this that we want is:
* u8 type
* u8 reserved_zero[3]
*
* But it turns out that by encoding this as little endian,
* we achieve the same thing, and it makes checking faster.
*/
// MOD : trash field to change message size and add 4 byte offset to all fields
__le32 trash;
__le32 type;
};
--------------------------------------
Напишем функцию для генерации trash. Функция должна быть быстрая, важно не замедлить скорость.
Мы не расчитываем, что нас будут специально ловить, иначе бы пришлось делать полноценный обфускатор.
Задача лишь сломать стандартный модуль обнаружения протокола wireguard. Потому истинная рандомность
trash не важна.
Но все же немного "трэша" не повредит. Гонки между тредами так же пофигистичны. Это же трэш.
--noise.c-----------------------------
// MOD : trash generator
__le32 gtrash = 0;
__le32 gen_trash(void)
{
if (gtrash)
gtrash = gtrash*1103515243 + 12345;
else
// first value is true random
get_random_bytes_wait(&gtrash, sizeof(gtrash));
return gtrash;
}
--------------------------------------
Теперь осталось найти все места, где создаются сообщения и внести туда заполнение поля trash.
Сообщений всего 4. Их можно найти по присваиванию полю type одного из значений enum message_type.
2 места в noise.c в функциях wg_noise_handshake_create_initiation и wg_noise_handshake_create_response,
1 место в cookie.c в функции wg_cookie_message_create
Дописываем в конец инициализации структуры сообщения :
--------------------------------------
// MOD : randomize trash
dst->header.trash = gen_trash();
--------------------------------------
и 1 место в send.c в функции encrypt_packet
--------------------------------------
// MOD : randomize trash
header->header.trash = gen_trash();
--------------------------------------
Вот и весь патчинг. Полный patch (версия wireguard 0.0.20190123) лежит в 010-wg-mod.patch.
Патчинг кода - самое простое. Для десктопного linux дальше все просто.
Пересобираем через make, устанавливаем через make install, перегружаем
модуль wireguard, перезапускаем интерфейсы, и все готово.
Настоящий геморой начнется когда вы это попытаетесь засунуть на роутер под openwrt.
Одна из больших проблем linux - отсутствие совместимости драйверов на уровне бинариков.
Поэтому собирать необходимо в точности под вашу версию ядра и в точности под его .config.
Вам придется либо полностью самостоятельно собирать всю прошивку, либо найти SDK в точности
от вашей версии прошивки для вашей архитектуры и собрать модуль с помощью этого SDK.
Последний вариант более легкий.
Для сборки вам понадобится система на linux x86_64. Ее можно установить в виртуалке.
Теоретически можно пользоваться WSL из win10, но на практике там очень медленное I/O,
по крайней мере на старых версиях win10. Безумно медленное. Будете собирать вечность.
Может в новых win10 что-то и улучшили, но я бы сразу расчитывал на полноценный linux.
Находим здесь вашу версию : https://downloads.openwrt.org/
Скачиваем файл openwrt-sdk-*.tar.xz или lede-sdk-*.tar.xz
Например : https://downloads.openwrt.org/releases/18.06.2/targets/ar71xx/generic/openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64.tar.xz
Если ваша версия непонятна или стара, то проще будет найти последнюю прошивку и перешить роутер.
Распаковываем SDK. Следующими командами можно собрать оригинальный вариант wireguard :
# scripts/feeds update -a
# scripts/feeds install -a
# make defconfig
# make -j 4 package/wireguard/compile
Сборка будет довольно долгой. Ведь придется подтащить ядро, собрать его, собрать зависимости.
"-j 4" означает использовать 4 потока. Впишите вместо 4 количество доступных cpu cores.
Получим следующие файлы :
openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/bin/targets/ar71xx/generic/packages/kmod-wireguard_4.9.152+0.0.20190123-1_mips_24kc.ipk
openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/bin/packages/mips_24kc/base/wireguard-tools_0.0.20190123-1_mips_24kc.ipk
Но это будет оригинальный wireguard. Нам нужен патченый.
Установим quilt и mc для нормального редактора вместо vim :
# sudo apt-get update
# sudo apt-get install quilt mc
# make package/wireguard/clean
# make package/wireguard/prepare V=s QUILT=1
Сорцы приготовлены для сборки в :
openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src
# cd build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src
# quilt push -a
# quilt new 010-wg-mod.patch
# export EDITOR=mcedit
Далее будет открываться редактор mcedit, в который нужно вносить изменения в каждый файл :
# quilt edit messages.h
# quilt edit cookie.c
# quilt edit noise.c
# quilt edit send.c
# quilt diff
# quilt refresh
Получили файл патча в :
openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/patches/010-wg-mod.patch
Выходим в корень SDK.
# make package/wireguard/compile V=99
Если не было ошибок, то получили измененные ipk.
Патч можно зафиксировать в описании пакета :
# make package/wireguard/update
Получим :
openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/feeds/base/package/network/services/wireguard/patches/010-wg-mod.patch
При последующей очистке и пересборке он будет автоматом применяться.
АЛЬТЕРНАТИВА : можно не возиться с quilt.
сделайте
# make package/wireguard/clean
# make package/wireguard/prepare
и напрямую модифицируйте или копируйте файлы в
openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/WireGuard-0.0.20190123/src
затем
# make package/wireguard/compile
Если нужно поменять версию wireguard, то идите в
openwrt-sdk-18.06.2-ar71xx-generic_gcc-7.3.0_musl.Linux-x86_64/feeds/base/package/network/services/wireguard/Makefile
поменяйте там версию в PKG_VERSION на последнюю из : https://git.zx2c4.com/WireGuard
скачайте tar.xz с этой версией , вычислите его sha256sum, впишите в PKG_HASH
1 раз где-нибудь пропатчите файлы последней версии wireguard в текстовом редакторе, скопируйте в build_dir,
сделайте версию для openwrt. эти же файлы скопируйте на ваш сервер с десктопным linux, сделайте там make / make install
Но имейте в виду, что build_dir - локация для временных файлов.
make clean оттуда все снесет, включая ваши модификации. Модифицированные файлы лучше сохранить отдельно,
чтобы потом было легко скопировать обратно.
Полученные ipk копируем на роутер в /tmp, устанавливаем через
# cd /tmp
# rm -r /tmp/opkg-lists
# opkg install *.ipk
Если требует зависимостей, то
# opkg update
# opkg install .... <зависимости>
# rm -r /tmp/opkg-lists
# opkg install *.ipk
В /tmp/opkg-lists opkg хранит кэш списка пакетов. Если попытаться установить файл ipk, и такой же пакет
найдется в репозитории, opkg будет устанавливать из репозитория. А нам это не надо.
# rmmod wireguard
# kmodloader
# dmesg | tail
должны увидеть что-то вроде :
[8985.415490] wireguard: WireGuard 0.0.20190123 loaded. See www.wireguard.com for information.
[8985.424178] wireguard: Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
значит модуль загрузился
Могут понадобиться ключи opkg --force-reinstall, --force-depends.
--force-depends поможет при несоответствии hash версии ядра. То есть версия x.x.x та же самая, но hash конфигурации разный.
При несоответствии x.x.x вы что-то делаете не так, работать это не будет.
Например : 4.14.56-1-b1186491495127cc6ff81d29c00a91fc, 4.14.56-1-3f8a21a63974cfb7ee67e41f2d4b805d
Это свидетельствует о несоответствии .config ядра при сборке прошивки и в SDK.
Если несоответствие легкое, то может все прокатить, но при более серьезной разнице в .config модуль может не загрузиться
или вызвать стабильные или хаотические падения ядра и перезагрузки (включая вариант беонечной перезагрузки - bootloop).
Так что перед --force-depends убедитесь, что знаете как лечится такая ситуация, и не стоит это делать при отсутствии физического
доступа к девайсу.
Когда поднимите линк, и вдруг ничего не будет работать, то посмотрите в wireshark udp пакеты
на порт endpoint. Они не должны начинаться с 0,1,2,3,4. В первых 4 байтах должен быть рандом,
в следующих 4 байтах - значения из измененного enum message_type. Если пакет все еще начинается с 0..4,
значит модуль wireguard оригинальный, что-то не собралось, не скопировалось, не перезапустилось.
В противном случае должен подняться линк, пинги ходить. Значит вы победили, поздравляю.
Регулятору будет намного сложнее поймать ваш VPN.

View File

@@ -0,0 +1,645 @@
Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему.
Если вы не знаете основ сетей, linux, openwrt, а пытаетесь что-то скопипастить отсюда без малейшего
понимания смысла, то маловероятно, что у вас что-то заработает. Не тратье свое время напрасно.
Цель - донести принципы как это настраивается вообще, а не указать какую буковку где вписать.
Есть возможность поднять свой VPN сервер ? Не хотим использовать redsocks ?
Хотим завертывать на VPN только часть трафика ?
Например, из ipset zapret только порт tcp:443, из ipban - весь трафик, не только tcp ?
Да, с VPN такое возможно.
Опишу понятийно как настраивается policy based routing в openwrt на примере wireguard.
Вместо wireguard можно использовать openvpn или любой другой. Но wireguard прекрасен сразу несколькими вещами.
Главная из которых - в разы большая скорость, даже немного превышающая ipsec.
Ведь openvpn основан на tun, а tun - всегда в разы медленнее решения в kernel mode,
и если для PC оно может быть не так актуально, для soho роутеров - более чем.
Wireguard может дать 50 mbps там, где openvpn еле тащит 10.
Но есть и дополнительное требование. Wireguard работает в ядре, значит ядро должно
быть под вашим контролем. vps на базе openvz не подойдет. Нужен xen, kvm,
любой другой вариант, где загружается ваше собственное ядро, а не используется
общее, разделяемое на множество vps.
Понятийно необходимо выполнить следующие шаги :
1) Поднять vpn сервер.
2) Настроить vpn клиент. Результат этого шага - получение поднятого интерфейса vpn.
Будь то wireguard, openvpn или любой другой тип vpn.
3) Создать такую схему маршрутизации, при которой пакеты, помечаемые особым mark,
попадают на vpn, а остальные идут обычным способом.
4) Создать правила, выставляющие mark для всего трафика, который необходимо рулить на vpn.
Критерии могут быть любые, ограниченные лишь возможностями iptables и вашим воображением.
Будем считать наш vpn сервер находится на ip 91.15.68.202.
Вешать его будем на udp порт 12345. На этот же порт будем вешать и клиентов.
Сервер работает под debian 9 или выше. Клиент работает под openwrt.
Для vpn отведем подсеть 192.168.254.0/24.
--- Если нет своего сервера ---
Но есть конфиг от VPN провайдера или от друга "Васи", который захотел с вами поделиться.
Тогда вам не надо настраивать сервер, задача упрощается. Делается невозможным вариант настройки
без masquerade (см ниже).
Из конфига вытаскиваете приватный ключ своего пира и публичный ключ сервера, ip/host/port сервера,
используете их в настройках openwrt вместо сгенеренных самостоятельно.
--- Поднятие сервера ---
Wireguard был включен в ядро linux с версии 5.6.
Если у вас ядро >=5.6, то достаточно установить пакет wireguard-tools. Он содержит user-mode компоненты wireguard.
Посмотрите, возможно в вашем дистрибутиве ядро по умолчанию более старое, но в репозитории
имеются бэкпорты новых версий. Лучше будет обновить ядро из репозитория.
В репозитории может быть пакет wireguard-dkms. Это автоматизированное средство сборки
wireguard с исходников, в том числе модуль ядра. Можно пользоваться им.
Иначе вам придется собрать wireguard самому. Ядро должно быть не ниже 3.10.
На сервере должны быть установлены заголовки ядра (linux-headers-...) и компилятор gcc.
# git clone --depth 1 https://git.zx2c4.com/wireguard-linux-compat
# cd wireguard-linux-compat/src
# make
# strip --strip-debug wireguard.ko
# sudo make install
wireguard основан на понятии криптороутинга. Каждый пир (сервер - тоже пир)
имеет пару открытый/закрытый ключ. Закрытый ключ остается у пира,
открытый прописывается у его партнера. Каждый пир авторизует другого
по знанию приватного ключа, соответствующего прописанному у него публичному ключу.
Протокол построен таким образом, что на все неправильные udp пакеты не следует ответа.
Не знаешь приватный ключ ? Не смог послать правильный запрос ? Долбись сколько влезет,
я тебе ничего не отвечу. Это защищает от активного пробинга со стороны DPI и просто
экономит ресурсы.
Значит первым делом нужно создать 2 пары ключей : для сервера и для клиента.
wg genkey генерит приватный ключ, wg pubkey получает из него публичный ключ.
# wg genkey
oAUkmhoREtFQ5D5yZmeHEgYaSWCcLYlKe2jBP7EAGV0=
# echo oAUkmhoREtFQ5D5yZmeHEgYaSWCcLYlKe2jBP7EAGV0= | wg pubkey
bCdDaPYSTBZVO1HTmKD+Tztuf3PbOWGDWfz7Lb1E6C4=
# wg genkey
OKXX0TSlyjJmGt3/yHlHxi0AqjJ0vh+Msne3qEHk0VM=
# echo OKXX0TSlyjJmGt3/yHlHxi0AqjJ0vh+Msne3qEHk0VM= | wg pubkey
EELdA2XzjcKxtriOCPBXMOgxlkgpbRdIyjtc3aIpkxg=
Пишем конфиг
--/etc/wireguard/wgvps.conf-------------------
[Interface]
PrivateKey = OKXX0TSlyjJmGt3/yHlHxi0AqjJ0vh+Msne3qEHk0VM=
ListenPort = 12345
[Peer]
#Endpoint =
PublicKey = bCdDaPYSTBZVO1HTmKD+Tztuf3PbOWGDWfz7Lb1E6C4=
AllowedIPs = 192.168.254.3
PersistentKeepalive=20
----------------------------------------------
Wireguard - минималистичный vpn. В нем нет никаких средств для автоконфигурации ip.
Все придется прописывать руками.
В wgvps.conf должны быть перечислены все пиры с их публичными ключами,
а так же прописаны допустимые для них ip адреса.
Назначим нашему клиенту 192.168.254.3. Сервер будет иметь ip 192.168.254.1.
Endpoint должен быть прописан хотя бы на одном пире.
Если endpoint настроен для пира, то wireguard будет периодически пытаться к нему подключиться.
В схеме клиент/сервер у сервера можно не прописывать endpoint-ы пиров, что позволит
менять ip и быть за nat. Endpoint пира настраивается динамически после успешной фазы
проверки ключа.
Включаем маршрутизцию :
# echo net.ipv4.ip_forward = 1 >>/etc/sysctl.conf
# sysctl -p
Интерфейс конфигурится стандартно для дебианоподобных систем :
--/etc/network/interfaces.d/wgvps-------------
auto wgvps
iface wgvps inet static
address 192.168.254.1
netmask 255.255.255.0
pre-up ip link add $IFACE type wireguard
pre-up wg setconf $IFACE /etc/wireguard/$IFACE.conf
post-up iptables -t nat -A POSTROUTING -o eth0 -s 192.168.254.0/24 -j MASQUERADE
post-up iptables -A FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
post-down iptables -D FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
post-down iptables -t nat -D POSTROUTING -o eth0 -s 192.168.254.0/24 -j MASQUERADE
post-down ip link del $IFACE
----------------------------------------------
Поднятие через ifup wgvps, опускание через ifdown wgvps.
При поднятии интерфейса заодно настраивается nat. eth0 здесь означает интерфейс vpn сервера с инетовским ip адресом.
Если у вас какая-то система управления фаерволом, то надо настройку nat прикручивать туда.
Пример написан для простейшего случая, когда никаких ограничений нет, таблицы iptables пустые.
Чтобы посмотреть текущие настройки wireguard, запустите 'wg' без параметров.
--- Поднятие клиента ---
# opkg update
# opkg install wireguard-tools
Добавляем записи в конфиги.
--/etc/config/network--------------------------
config interface 'wgvps'
option proto 'wireguard'
option auto '1'
option private_key 'oAUkmhoREtFQ5D5yZmeHEgYaSWCcLYlKe2jBP7EAGV0='
option listen_port '12345'
option metric '9'
option mtu '1420'
config wireguard_wgvps
option public_key 'EELdA2XzjcKxtriOCPBXMOgxlkgpbRdIyjtc3aIpkxg='
list allowed_ips '0.0.0.0/0'
option endpoint_host '91.15.68.202'
option endpoint_port '12345'
option route_allowed_ips '0'
option persistent_keepalive '20'
config interface 'wgvps_ip'
option proto 'static'
option ifname '@wgvps'
list ipaddr '192.168.254.3/24'
config route
option interface 'wgvps'
option target '0.0.0.0/0'
option table '100'
config rule
option mark '0x800/0x800'
option priority '100'
option lookup '100'
------------------------------------------------
--/etc/config/firewall--------------------------
config zone
option name 'tunvps'
option output 'ACCEPT'
option input 'REJECT'
option masq '1'
option mtu_fix '1'
option forward 'REJECT'
option network 'wgvps wgvps_ip'
config forwarding
option dest 'tunvps'
option src 'lan'
config rule
option name 'Allow-ICMP-tunvps'
option src 'tunvps'
option proto 'icmp'
option target 'ACCEPT'
config rule
option target 'ACCEPT'
option src 'wan'
option proto 'udp'
option family 'ipv4'
option src_port '12345'
option src_ip '91.15.68.202'
option name 'WG-VPS'
------------------------------------------------
Что тут было сделано :
*) Настроен интерфейс wireguard. Указан собственный приватный ключ.
*) Настроен пир-партнер с указанием его публичнго ключа и endpoint (ip:port нашего сервера)
такая настройка заставит периодически долбиться на сервер по указанному ip
route_allowed_ip '0' запрещает автоматическое создание маршрута
allowed_ips '0.0.0.0/0' разрешает пакеты с любым адресом источника.
ведь мы собираемся подключаться к любым ip в инете
persistent_keepalive '20' помогает исключить дропание mapping на nat-е, если мы сидим за ним,
да и вообще полезная вещь, чтобы не было подвисших пиров
*) Статическая конфигурация ip интерфейса wgvps.
*) Маршрут default route на wgvps в отдельной таблице маршрутизации с номером 100. Аналог команды ip route add .. table 100
*) Правило использовать таблицу 100 при выставлении в mark бита 0x800. Аналог команды ip rule.
*) Отдельная зона фаервола для VPN - 'tunvps'. В принципе ее можно не создавать, можете приписать интерфейс к зоне wan.
Но в случае с отдельной зоной можно настроить особые правила на подключения с vpn сервера в сторону клиента.
*) Разрешение форвардинга между локалкой за роутером и wgvps.
*) Разрешение принимать icmp от vpn сервера, включая пинги. ICMP жизненно важны для правильного функционирования ip сети !
*) И желательно проткнуть дырку в фаерволе, чтобы принимать пакеты wireguard со стороны инетовского ip vpn сервера.
Конечно, оно скорее всего заработает и так, потому что первый пакет пойдет от клиента к серверу и тем самым создаст
запись в conntrack. Все дальнейшие пакеты в обе стороны подпадут под состояние ESTABLISHED и будут пропущены.
Запись будет поддерживаться за счет периодических запросов keep alive. Но если вы вдруг уберете keep alive или
выставите таймаут, превышающий udp таймаут в conntrack, то могут начаться ошибки, висы и переподключения.
Если же в фаерволе проткнута дырка, то пакеты от сервера не будут заблокированы ни при каких обстоятельствах.
# /etc/init.d/firewall restart
# ifup wgvps
# ifconfig wgvps
# ping 192.168.254.1
Если все хорошо, должны ходить пинги.
С сервера не помешает :
# ping 192.168.254.3
--- Подготовка zapret ---
Выполните install_easy.sh. Он настроит режим обхода DPI. Если обход DPI не нужен - выберите MODE=filter.
Так же инсталятор заресолвит домены из ipset/zapret-hosts-user-ipban.txt и внесет крон-джоб для периодического обновления ip.
Если вы используете в своих правилах ipset zapret, то он ресолвится и обновляется только, если выбран режим фильтрации обхода DPI по ipset.
По сути он вам нужен исключительно, если обход DPI не помогает. Например, удается как-то пробить http, но не удается пробить https.
И при этом вы хотите, чтобы на VPN направлялись только ip из скачанного ip листа, в добавок к заресолвленному ipset/zapret-hosts-user.txt.
Именно этот случай и рассмотрен в данном примере. Если это не так, то убирайте правила с портом 443 из нижеприведенных правил iptables/nftables.
Если не хотите ограничиваться листом, и хотите направлять все на порт 443, то уберите фильтры из правил iptables/nftables,
связанные с ipset/nfset "zapret".
Фильтрация по именам доменов (MODE_FILTER=hostlist) невозможна средствами iptables/nftables. Она производится исключительно в tpws и nfqws
по результатам анализа протокола прикладного уровня, иногда достаточно сложного, связанного с дешифровкой пакета (QUIC).
Скачиваются листы с именами доменов, не ip адресами. ipset/zapret-hosts-user.txt не ресолвится, а используется как hostlist.
Потому вам нельзя расчитывать на ipset zapret.
Тем не менее при выборе этого режима фильтрации , либо вовсе при ее отсутствии (MODE_FILTER=none), ipset/zapret-hosts-user-ipban.txt
все равно ресолвится. Вы всегда можете расчитывать на ipset/nfset "ipban", "nozapret".
"nozapret" - это ipset/nfset, связанный с системой исключения ip. Сюда загоняется все из ipset/zapret-hosts-user-exclude.txt после ресолвинга.
Его учет крайне желателен, чтобы вдруг из скачанного листа не просочились записи, например, 192.168.0.0/16 и не заставили лезть туда через VPN.
Хотя скрипты получения листов и пытаются отсечь IP локалок, но так будет намного надежнее.
--- Маркировка трафика ---
Завернем на vpn все из ipset zapret на tcp:443 и все из ipban.
OUTPUT относится к исходящим с роутера пакетам, PREROUTING - ко всем остальным.
Если с самого роутера ничего заруливать не надо, можно опустить часть, отвечающую за OUTPUT.
--/etc/firewall.user----------------------------
. /opt/zapret/init.d/openwrt/functions
create_ipset no-update
network_find_wan4_all wan_iface
for ext_iface in $wan_iface; do
network_get_device DEVICE $ext_iface
ipt OUTPUT -t mangle -o $DEVICE -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt OUTPUT -t mangle -o $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
done
network_get_device DEVICE lan
ipt PREROUTING -t mangle -i $DEVICE -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt PREROUTING -t mangle -i $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
------------------------------------------------
# /etc/init.d/firewall restart
--- Маркировка трафика nftables ---
В новых openwrt по умолчанию установлен nftables, iptables отсутствует.
Есть вариант снести nftables + fw4 и заменить их на iptables + fw3.
Веб интерфейс luci понимает прозрачно и fw3, и fw4. Однако, при установке iptables и fw3 новые пакеты
будут устанавливаться без сжатия squashfs. Убедитесь, что у вас достаточно места.
Либо сразу настраивайте образ через image builder.
Фаервол fw4 работает в одноименной nftable - "inet fw4". "inet" означает, что таблица принимает и ipv4, и ipv6.
Поскольку для маркировки трафика используется nfset, принадлежащий таблице zapret, цепочки необходимо помещать в ту же таблицу.
Для синхронизации лучше всего использовать хук
INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up"
Параметр нужно раскоментировать в /opt/zapret/config. Далее надо создать указанный файл и дать ему chmod 755.
--/etc/firewall.zapret.hook.post_up----------------------------
#!/bin/sh
ZAPRET_NFT_TABLE=zapret
cat << EOF | nft -f - 2>/dev/null
delete chain inet $ZAPRET_NFT_TABLE my_output
delete chain inet $ZAPRET_NFT_TABLE my_prerouting
EOF
cat << EOF | nft -f -
add chain inet $ZAPRET_NFT_TABLE my_output { type route hook output priority mangle; }
flush chain inet $ZAPRET_NFT_TABLE my_output
add rule inet $ZAPRET_NFT_TABLE my_output oifname @wanif ip daddr @ipban ip daddr != @nozapret meta mark set mark or 0x800
add rule inet $ZAPRET_NFT_TABLE my_output oifname @wanif tcp dport 443 ip daddr @zapret ip daddr != @nozapret meta mark set mark or 0x800
add chain inet $ZAPRET_NFT_TABLE my_prerouting { type filter hook prerouting priority mangle; }
flush chain inet $ZAPRET_NFT_TABLE my_prerouting
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname @lanif ip daddr @ipban ip daddr != @nozapret meta mark set mark or 0x800
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname @lanif tcp dport 443 ip daddr @zapret ip daddr != @nozapret meta mark set mark or 0x800
EOF
------------------------------------------------
# /etc/init.d/zapret restart_fw
Проверка правил :
# /etc/init.d/zapret list_table
или
# nft -t list table inet zapret
Должны быть цепочки my_prerouting и my_output.
Проверка заполнения nfsets :
# nft list set inet zapret zapret
# nft list set inet zapret ipban
# nft list set inet zapret nozapret
Проверка заполнения множеств lanif, wanif, wanif6, link_local :
# /etc/init.d/zapret list_ifsets
Должны присутствовать имена интерфейсов во множествах lanif, wanif.
wanif6 заполняется только при включении ipv6.
link_local нужен только для tpws при включении ipv6.
--- По поводу двойного NAT ---
В описанной конфигурации nat выполняется дважды : на роутере-клиенте происходит замена адреса источника из LAN
на 192.168.254.3 и на сервере замена 192.168.254.3 на внешний адрес сервера в инете.
Зачем так делать ? Исключительно для простоты настройки. Или на случай, если сервер wireguard не находится под вашим контролем.
Делать для вас нижеописанные настройки никто не будет с вероятностью, близкой к 100%.
Если сервер wireguard - ваш, и вы готовы чуток еще поднапрячься и не хотите двойного nat,
то можете вписать в /etc/config/firewall "masq '0'", на сервер дописать маршрут до вашей подсети lan.
Чтобы не делать это для каждого клиента, можно отвести под всех клиентов диапазон 192.168.0.0-192.168.127.255
и прописать его одним маршрутом.
--/etc/network/interfaces.d/wgvps-------------
post-up ip route add dev $IFACE 192.168.0.0/17
post-down ip route del dev $IFACE 192.168.0.0/17
----------------------------------------------
Так же необходимо указать wireguard дополнительные разрешенные ip для peer :
--/etc/wireguard/wgvps.conf-------------------
[Peer]
PublicKey = bCdDaPYSTBZVO1HTmKD+Tztuf3PbOWGDWfz7Lb1E6C4=
AllowedIPs = 192.168.254.3, 192.168.2.0/24
----------------------------------------------
Всем клиентам придется назначать различные диапазоны адресов в lan и индивидуально прописывать AllowedIPs
для каждого peer.
# ifdown wgvps ; ifup wgvps
На клиенте разрешим форвард icmp, чтобы работал пинг и корректно определялось mtu.
--/etc/config/firewall--------------------------
config rule
option name 'Allow-ICMP-tunvps'
option src 'tunvps'
option dest 'lan'
option proto 'icmp'
option target 'ACCEPT'
------------------------------------------------
Существуют еще два неочевидных нюанса.
Первый из них касается пакетов с самого роутера (цепочка OUTPUT).
Адрес источника выбирается по особому алгоритму, если программа явно его не задала, еще до этапа iptables.
Он берется с интерфейса, куда бы пошел пакет при нормальном раскладе.
Обратная маршрутизация с VPN станет невозможной, да и wireguard такие пакеты порежет, поскольку они не вписываются в AllowedIPs.
Никаким мистическим образом автоматом source address не поменяется.
В прошлом варианте настройки проблема решалось через маскарад. Сейчас же маскарада нет.
Потому все же придется его делать в случае, когда пакет изначально направился бы через wan,
а мы его завертываем на VPN. Помечаем такие пакеты марком 0x1000.
Если вам не актуальны исходящие с самого роутера, то можно ничего не менять.
Другой нюанс связан с обработкой проброшенных на vps портов, соединения по которым приходят как входящие с интерфейса wgvps.
Представьте себе, что вы пробросили порт 2222. Кто-то подключается с адреса 1.2.3.4. Вам приходит пакет SYN 1.2.3.4:51723=>192.168.2.2:2222.
По правилам маршрутизации он пойдет в локалку. 192.168.2.2 его обработает, ответит пакетом ACK 192.168.2.2:2222=>1.2.3.4:51723.
Этот пакет придет на роутер. И куда он дальше пойдет ? Если он не занесен в ipban, то согласно правилам машрутизации
он пойдет по WAN интерфейсу, а не по исходному wgvps.
Чтобы решить эту проблему, необходимо воспользоваться CONNMARK. Существуют 2 отдельных марка : fwmark и connmark.
connmark относится к соединению, fwmark - к пакету. Трэкингом соединений занимается conntrack.
Посмотреть его таблицу можно командой "conntrack -L". Там же найдете connmark : mark=xxxx.
Как только видим приходящий с wgvps пакет с новым соединением, отмечаем его connmark как 0x800/0x800.
При этом fwmark не меняется, иначе бы пакет тут же бы завернулся обратно на wgvps согласно ip rule.
Если к нам приходит пакет с какого-то другого интерфейса, то восстанавливаем его connmark в fwmark по маске 0x800.
И теперь он подпадает под правило ip rule, заворачиваясь на wgvps, что и требовалось.
Альтернативное решение - использовать на VPSке для проброса портов не только DNAT, но и SNAT/MASQUERADE. Тогда source address
будет заменен на 192.168.254.1. Он по таблице маршрутизации пойдет на wgvps. Но в этом случае клиентские программы,
на которые осуществляется проброс портов, не будут видеть реальный IP подключенца.
--/etc/firewall.user----------------------------
. /opt/zapret/init.d/openwrt/functions
create_ipset no-update
network_find_wan4_all wan_iface
for ext_iface in $wan_iface; do
network_get_device DEVICE $ext_iface
ipt OUTPUT -t mangle -o $DEVICE -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt OUTPUT -t mangle -o $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt OUTPUT -t mangle -o $DEVICE -j MARK --set-mark 0x1000/0x1000
done
network_get_device DEVICE lan
ipt PREROUTING -t mangle -i $DEVICE -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt PREROUTING -t mangle -i $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
# do masquerade for OUTPUT to ensure correct outgoing address
ipt postrouting_tunvps_rule -t nat -m mark --mark 0x1000/0x1000 -j MASQUERADE
# incoming from wgvps
network_get_device DEVICE wgvps
ipt PREROUTING -t mangle ! -i $DEVICE -j CONNMARK --restore-mark --nfmask 0x800 --ctmask 0x800
ipt PREROUTING -t mangle -i $DEVICE -m conntrack --ctstate NEW -j CONNMARK --set-mark 0x800/0x800
------------------------------------------------
# /etc/init.d/firewall restart
Вариант nftables :
--/etc/firewall.zapret.hook.post_up----------------------------
#!/bin/sh
ZAPRET_NFT_TABLE=zapret
DEVICE=wgvps
cat << EOF | nft -f - 2>/dev/null
delete chain inet $ZAPRET_NFT_TABLE my_output
delete chain inet $ZAPRET_NFT_TABLE my_prerouting
delete chain inet $ZAPRET_NFT_TABLE my_nat
EOF
cat << EOF | nft -f -
add chain inet $ZAPRET_NFT_TABLE my_output { type route hook output priority mangle; }
flush chain inet $ZAPRET_NFT_TABLE my_output
add rule inet $ZAPRET_NFT_TABLE my_output oifname @wanif ip daddr @ipban ip daddr != @nozapret meta mark set mark or 0x800
add rule inet $ZAPRET_NFT_TABLE my_output oifname @wanif tcp dport 443 ip daddr @zapret ip daddr != @nozapret meta mark set mark or 0x800
add rule inet $ZAPRET_NFT_TABLE my_output oifname @wanif meta mark set mark or 0x1000
add chain inet $ZAPRET_NFT_TABLE my_prerouting { type filter hook prerouting priority mangle; }
flush chain inet $ZAPRET_NFT_TABLE my_prerouting
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname $DEVICE ct state new ct mark set ct mark or 0x800
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname != $DEVICE meta mark set ct mark and 0x800
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname @lanif ip daddr @ipban ip daddr != @nozapret meta mark set mark or 0x800
add rule inet $ZAPRET_NFT_TABLE my_prerouting iifname @lanif tcp dport 443 ip daddr @zapret ip daddr != @nozapret meta mark set mark or 0x800
add chain inet $ZAPRET_NFT_TABLE my_nat { type nat hook postrouting priority 100 ; }
flush chain inet $ZAPRET_NFT_TABLE my_nat
add rule inet $ZAPRET_NFT_TABLE my_nat oifname $DEVICE mark and 0x1000 == 0x1000 masquerade
EOF
------------------------------------------------
# /etc/init.d/zapret restart_fw
К сожалению, здесь возможности nftables немного хромают. Полноценного эквивалента CONNMARK --restore-mark --nfmask
не существует. Оригинал iptables предполагал копирование одного бита 0x800 из connmark в mark.
Лучшее, что можно сделать в nftables, это копирование одного бита с занулением всех остальных.
Сложные выражения типа "meta mark set mark and ~0x800 or (ct mark and 0x800)" nft не понимает.
Об этом же говорит попытка перевода через iptables-translate.
Сейчас уже можно с vpn сервера пингануть ip адрес внутри локалки клиента. Пинги должны ходить.
Отсутствие двойного NAT значительно облегчает проброс портов с внешнего IP vpn сервера в локалку какого-либо клиента.
Для этого надо выполнить 2 действия : добавить разрешение в фаервол на клиенте и сделать dnat на сервере.
Пример форварда портов 5001 и 5201 на 192.168.2.2 :
--/etc/config/firewall--------------------------
config rule
option target 'ACCEPT'
option src 'tunvps'
option dest 'lan'
option proto 'tcp udp'
option dest_port '5001 5201'
option dest_ip '192.168.2.2'
option name 'IPERF'
------------------------------------------------
# /etc/init.d/firewall restart
# /etc/init.d/zapret restart_fw
--/etc/network/interfaces.d/wgvps-------------
post-up iptables -t nat -A PREROUTING -i eth0 -p tcp -m multiport --dports 5001,5201 -j DNAT --to-destination 192.168.2.2
post-up iptables -t nat -A PREROUTING -i eth0 -p udp -m multiport --dports 5001,5201 -j DNAT --to-destination 192.168.2.2
post-down iptables -t nat -D PREROUTING -i eth0 -p tcp -m multiport --dports 5001,5201 -j DNAT --to-destination 192.168.2.2
post-down iptables -t nat -D PREROUTING -i eth0 -p udp -m multiport --dports 5001,5201 -j DNAT --to-destination 192.168.2.2
----------------------------------------------
# ifdown wgvps ; ifup wgvps
Пример приведен для iperf и iperf3, чтобы показать как пробрасывать несколько портов tcp+udp с минимальным количеством команд.
Проброс tcp и udp порта так же необходим для полноценной работы bittorrent клиента, чтобы работали входящие.
--- Как мне отправлять на vpn весь трафик с bittorrent ? ---
Можно поступить так : посмотрите порт в настройках torrent клиента, убедитесь, что не поставлено "случайный порт",
добавьте на роутер правило маркировки по порту источника.
Но мне предпочтительно иное решение. На windows есть замечательная возможность
прописать правило установки поля качества обслуживания в заголовках ip пакетов в зависимости от процесса-источника.
Для windows 7/2008R2 необходимо будет установить ключик реестра и перезагрузить комп :
# reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\QoS /v "Do not use NLA" /t REG_SZ /d "1"
Редактировать политику можно в : gpedit.msc -> Computer Configuration -> Windows Settings -> Policy-based QoS
На win 10 ключик реестра больше не работает, правила qos в gpedit применяются только для профиля домена.
Необходимо пользоваться командой powershell New-NetQosPolicy. Гуглите хелп по ней. Пример :
# powershell New-NetQosPolicy -Name "torrent" -AppPathNameMatchCondition "qbittorrent.exe" -DSCPAction 1
Однозначно требуется проверка в wireshark или netmon успешности установки поля dscp. Если там по-прежнему 0x00,
значит что-то не сработало. 0x04 означает DSCP=1 (dscp находится в старших 6 битах).
На роутере в фаер прописываем правило :
--/etc/config/firewall--------------------------
config rule
option target 'MARK'
option src 'lan'
option proto 'all'
option extra '-m dscp --dscp 1'
option name 'route-dscp-1'
option set_mark '0x0800/0x0800'
------------------------------------------------
# /etc/init.d/firewall restart
Теперь все с полем dscp "1" идет на vpn. Клиент сам решает какой трафик ему нужно забрасывать
на vpn, перенастраивать роутер не нужно.
На linux клиенте проще всего будет выставлять dscp в iptables по номеру порта источника :
--/etc/rc.local---------------------------------
iptables -A OUTPUT -t mangle -p tcp --sport 23444 -j DSCP --set-dscp 1
iptables -A OUTPUT -t mangle -p udp --sport 23444 -j DSCP --set-dscp 1
------------------------------------------------
можно привязываться к pid процесса, но тогда нужно перенастраивать iptables при каждом перезапуске
торент клиента, это требует рута, и все становится очень неудобно.
--- Автоматизация проброса портов через miniupnd ---
Да, его тоже можно использовать на vps. Только как всегда есть нюансы.
miniupnpd поддерживает 3 протокола IGD : upnp,nat-pmp и pcp.
upnp и pcp работают через мультикаст, который не пройдет через wgvps.
nat-pmp работает через посылку специальных сообщений на udp:5351 на default gateway.
Обычно их обслуживает miniupnpd на роутере. При создании lease miniupnpd добавляет
правила для проброса портов в цепочку iptables MINIUPNPD, при потери lease - убирает.
udp:5351 можно перенаправить на vpn сервер через DNAT, чтобы их обрабатывал miniupnpd там.
Но вы должны иметь однозначный критерий перенаправления.
Если вы решили завернуть на vpn все, то проблем нет. Пробрасываем udp:5351 безусловно.
Если у вас идет перенаправление только с торрент, то необходимо к условию перенаправления
добавить условия, выделяющие torrent трафик из прочего. Или по dscp, или по sport.
Чтобы запросы от остальных программ обрабатывались miniupnpd на роутере.
Если какая-то программа создаст lease не там, где нужно, то входящий трафик до нее не дойдет.
На роутере стоит запретить протокол upnp, чтобы торрент клиент не удовлетворился запросом,
обслуженным по upnp на роутере, и пытался использовать nat-pmp.
--/etc/config/upnp--------------------------
config upnpd 'config'
.....
option enable_upnp '0'
------------------------------------------------
/etc/init.d/miniupnpd restart
Делаем проброс порта на роутере.
Для простоты изложения будем считать, что на vpn у нас завернут весь трафик.
Если это не так, то следует добавить фильтр в "config redirect".
Заодно выделяем диапазон портов для торрент клиентов.
Порт в торент клиенте следует прописать какой-то из этого диапазона.
------------------------------------------------
config redirect
option enabled '1'
option target 'DNAT'
option src 'lan'
option dest 'tunvps'
option proto 'udp'
option src_dport '5351'
option dest_ip '192.168.254.1'
option dest_port '5351'
option name 'NAT-PMP'
option reflection '0'
config rule
option enabled '1'
option target 'ACCEPT'
option src 'tunvps'
option dest 'lan'
option name 'tunvps-torrent'
option dest_port '28000-28009'
------------------------------------------------
/etc/init.d/firewall reload
На сервере :
apt install miniupnpd
--- /etc/miniupnpd/miniupnpd.conf --------
enable_natpmp=yes
enable_upnp=no
lease_file=/var/log/upnp.leases
system_uptime=yes
clean_ruleset_threshold=10
clean_ruleset_interval=600
force_igd_desc_v1=no
listening_ip=192.168.254.1/16
ext_ifname=eth0
------------------------------------------
systemctl restart miniupnpd
listening_ip прописан именно таким образом, чтобы обозначить диапазон разрешенных IP.
С других IP он не будет обрабатывать запросы на редирект.
В ext_ifname впишите название inet интерфейса на сервере.
Запускаем торрент клиент. Попутно смотрим в tcpdump весь путь udp:5351 до сервера и обратно.
Смотрим syslog сервера на ругань от miniupnpd.
Если все ок, то можем проверить редиректы : iptables -t nat -nL MINIUPNPD
С какого-нибудь другого хоста (не vpn сервер, не ваше подключение) можно попробовать telnet-нуться на проброшенный порт.
Должно установиться соединение. Или качайте торент и смотрите в пирах флаг "I" (incoming).
Если "I" есть и по ним идет закачка, значит все в порядке.
ОСОБЕННОСТЬ НОВЫХ DEBIAN : по умолчанию используются iptables-nft. miniupnpd работает с iptables-legacy.
ЛЕЧЕНИЕ : update-alternatives --set iptables /usr/sbin/iptables-legacy