Format BSD documentation

This commit is contained in:
toiletbril 2023-10-03 19:15:04 +03:00
parent 4f68b9b005
commit 9177e6fc06

View File

@ -1,3 +1,16 @@
## 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 ## Supported versions
FreeBSD 11.x+ , OpenBSD 6.x+, partially MacOS Sierra+ FreeBSD 11.x+ , OpenBSD 6.x+, partially MacOS Sierra+
@ -6,70 +19,85 @@ Older versions may work or not.
## BSD features ## BSD features
BSD does not have NFQUEUE. Similar mechanism - divert sockets. BSD does not have NFQUEUE. Similar mechanism - divert sockets. In BSD compiling
In BSD compiling the source from nfq directory result in dvtws binary instead of nfqws. 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. `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. FreeBSD has 3 firewalls: IPFilter, ipfw and Packet Filter (PF). OpenBSD has
only PF.
To compile sources in FreeBSD use `make`, in OpenBSD - use `make bsd`, in MacOS - use `make mac`. To compile sources:
Compile all programs : `make -C /opt/zapret` - FreeBSD: `make`
- OpenBSD: `make bsd`
- MacOS: `make mac`
Divert sockets are internal type sockets in the BSD kernel. They have no relation to network addresses Compile all programs:
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. make -C /opt/zapret
If nobody listens on the specified divert port packets are dropped. Its similar to NFQUEUE without `--queue-bypass`. ```
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. `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. 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 ipfw is absent scripts check LISTS_RELOAD config variable.
- If its present then scripts execute a command from LISTS_RELOAD. - If its present then scripts execute a command from LISTS_RELOAD.
- If LISTS_RELOAD=- scripts do not load tables even if ipfw exists. - 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 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. 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. BSD kernel doesn't implement splice syscall. tpws uses regular recv/send
Its slower but not critical. 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. `tpws` uses nonblocking sockets with linux specific epoll feature. In BSD systems
BSD systems have many limitations, version specific features and bugs in low level networking, especially for ipv6. epoll is emulated by epoll-shim library on top of kqueue.
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. `dvtws` uses some programming HACKs, assumptions and knowledge of discovered
It works for the moment but who knows. Such a usage is not very documented. 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.
mdig and ip2net are fully compatible with BSD.
## FreeBSD ## FreeBSD
Divert sockets require special kernel module 'ipdivert'. Divert sockets require special kernel module `ipdivert`.
Write the following to config files : Write the following to config files:
/boot/loader.conf (create if absent) : `/boot/loader.conf` (create if absent):
``` ```
ipdivert_load="YES" ipdivert_load="YES"
net.inet.ip.fw.default_to_accept=1 net.inet.ip.fw.default_to_accept=1
``` ```
/etc/rc.conf : `/etc/rc.conf`:
``` ```
firewall_enable="YES" firewall_enable="YES"
firewall_script="/etc/rc.firewall.my" firewall_script="/etc/rc.firewall.my"
``` ```
/etc/rc.firewall.my : `/etc/rc.firewall.my`:
``` ```
ipfw -q -f flush ipfw -q -f flush
``` ```
Later you will add ipfw commands to `/etc/rc.firewall.my` to be reapplied after reboot. 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 : You can also run zapret daemons from there. Start them with `--daemon` options, for example
``` ```
pkill ^dvtws$ pkill ^dvtws$
/opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2 /opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2
@ -77,9 +105,9 @@ pkill ^dvtws$
To restart firewall and daemons run : `/etc/rc.d/ipfw restart` To restart firewall and daemons run : `/etc/rc.d/ipfw restart`
Assume `LAN=em1`, `WAN="em0"`. Assume `LAN="em1"`, `WAN="em0"`.
tpws transparent mode quick start. `tpws` transparent mode quick start.
For all traffic: For all traffic:
``` ```
@ -91,7 +119,7 @@ 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 /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 : Process only table zapret with the exception of table nozapret:
``` ```
ipfw delete 100 ipfw delete 100
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 ipfw add 100 allow tcp from me to table\(nozapret\) 80,443
@ -103,21 +131,25 @@ 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 /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. Tables zapret, nozapret, ipban are created by `ipset/*.sh` scripts the same way as in Linux.
Its a good idea to update tables periodically : Its a good idea to update tables periodically:
``` ```
crontab -e 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. Write the line:
However without root its not possible to bind to ports <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. 0 12 */2 * * /opt/zapret/ipset/get_config.sh
Redirecting to ports >=1024 is dangerous. If tpws is not running any unprivileged process can ```
listen to that port and intercept traffic.
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. ### `dvtws` quick start
For all traffic: For all traffic:
``` ```
@ -126,7 +158,7 @@ ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 /opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
``` ```
Process only table zapret with the exception of table nozapret : Process only table zapret with the exception of table nozapret:
``` ```
ipfw delete 100 ipfw delete 100
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 ipfw add 100 allow tcp from me to table\(nozapret\) 80,443
@ -134,59 +166,68 @@ ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 /opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2
``` ```
Reinjection loop avoidance. Reinjection loop avoidance. FreeBSD artificially ignores sockarg for ipv6 in
FreeBSD artificially ignores sockarg for ipv6 in the kernel. the kernel. This limitation is coming from the ipv6 early age. Code is still in
This limitation is coming from the ipv6 early age. Code is still in "testing" state. 10-20 years. Everybody forgot about it. "testing" state. 10-20 years. Everybody forgot about it. `dvtws` sends ipv6
dvtws sends ipv6 forged frames using another divert socket (HACK). they can be filtered out using 'diverted'. forged frames using another divert socket (HACK). they can be filtered out
ipv4 frames are filtered using 'sockarg'. using 'diverted'. ipv4 frames are filtered using 'sockarg'.
### PF in FreeBSD
PF in FreeBSD:
The setup is similar to OpenBSD, but there are important nuances. The setup is similar to OpenBSD, but there are important nuances.
1) PF support is disabled by default in FreeBSD. Use parameter `--enable-pf`. 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. 2. It's not possible to redirect to `::1`. Need to redirect to the link-local
Look for fe80:... address in ifconfig and use it for redirection target. address of the incoming interface. Look for fe80:... address in ifconfig and
3) pf.conf syntax is a bit different from OpenBSD. use it for redirection target.
4) How to set maximum table size : sysctl net.pf.request_maxcount=2000000 3. pf.conf syntax is a bit different from OpenBSD.
5) The word 'divert-packet' is absent in the pfctl binary, divert-packet rules are not working. 4. How to set maximum table size : sysctl net.pf.request_maxcount=2000000
'divert-to' is not the same thing. Looks like its not possible to use dvtws with PF in FreeBSD. 5. The word 'divert-packet' is absent in the pfctl binary, divert-packet rules
are not working. 'divert-to' is not the same thing. Looks like its not
possible to use `dvtws` with PF in FreeBSD.
/etc/pf.conf `/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 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 rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988
``` ```
then
Then:
``` ```
/opt/zapret/tpws/tpws --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force /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. Its not clear how to do rdr-to outgoing traffic. I could not make route-to
scheme work.
## pfsense ### `pfsense`
pfsense is based on FreeBSD. `pfsense` is based on FreeBSD. Binaries from `binaries/freebsd-x64` are
Binaries from `binaries/freebsd-x64` are compiled in FreeBSD 11 and should work. Use `install_bin.sh`. compiled in FreeBSD 11 and should work. Use `install_bin.sh`. pfsense uses pf
pfsense uses pf firewall which does not support divert. firewall which does not support divert. Fortunately ipfw and ipdivert modules
Fortunately ipfw and ipdivert modules are present and can be kldload-ed. are present and can be kldload-ed. In older versions it's also necessary to
In older versions it's also necessary to change firewall order using sysctl commands. change firewall order using sysctl commands. In newer versions those sysctl
In newer versions those sysctl parameters are absent but the system behaves as required without them. 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. 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. There's autostart script example in `init.d/pfsense`. It should be placed to
Write your ipfw rules and daemon start commands. `/usr/local/etc/rc.d` and edited. Write your ipfw rules and daemon start
Because git is absent the most convinient way to copy files is ssh. curl is present by default. 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. Copy zip with zapret files to `/opt` and unpack there as it's done in other
In this case run dvtws as `/opt/zapret/nfq/dvtws`. Or just copy `dvtws` to `/usr/local/sbin`. As you wish. systems. In this case run `dvtws` as `/opt/zapret/nfq/dvtws`. Or just copy
ipset scripts are working, cron is present. It's possible to renew lists. `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. 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`. Change `no` to `yes` in `/usr/local/etc/pkg/repos/FreeBSD.conf`. Then it
Then it becomes possible to install all the required software including git to download zapret from github directly. 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) `/usr/local/etc/rc.d/zapret.sh` (chmod 755)
``` ```
#!/bin/sh #!/bin/sh
@ -208,10 +249,12 @@ dvtws --daemon --port 989 --dpi-desync=split2
pfctl -d ; pfctl -e pfctl -d ; pfctl -e
``` ```
I could not make tpws work from ipfw. Looks like there's some conflict between two firewalls. I could not make tpws work from ipfw. Looks like there's some conflict between
Only PF redirection works. PF does not allow to freely add and delete rules. Only anchors can be reloaded. two firewalls. Only PF redirection works. PF does not allow to freely add and
To make an anchor work it must be referred from the main ruleset. But its managed by pfsense scripts. delete rules. Only anchors can be reloaded. To make an anchor work it must be
One possible solution would be to modify '/etc/inc/filter.inc' as follows : 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 */ /* MOD */
@ -223,21 +266,22 @@ One possible solution would be to modify '/etc/inc/filter.inc' as follows :
................. .................
``` ```
Write the anchor code to '/etc/zapret.anchor': 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 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 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. 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' : Autostart `/usr/local/etc/rc.d/zapret.sh`:
``` ```
pfctl -a zapret -f /etc/zapret.anchor pfctl -a zapret -f /etc/zapret.anchor
pkill ^tpws$ 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 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 : After reboot check that anchor is created and referred from the main ruleset:
``` ```
[root@pfSense /]# pfctl -s nat [root@pfSense /]# pfctl -s nat
no nat proto carp all no nat proto carp all
@ -258,41 +302,47 @@ rdr pass on em1 inet6 proto tcp from any to any port = https -> fe80::20c:29ff:5
## OpenBSD ## OpenBSD
In OpenBSD default tpws bind is ipv6 only. to bind to ipv4 specify --bind-addr=0.0.0.0 In OpenBSD default `tpws` bind is ipv6 only. To bind to ipv4 specify
Use --bind-addr=0.0.0.0 --bind-addr=:: to achieve the same default bind as in others OSes. `--bind-addr=0.0.0.0`.
tpws for forwarded traffic only : Use `--bind-addr=0.0.0.0 --bind-addr=::` to achieve the same default bind as in
others OSes.
/etc/pf.conf `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 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 pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
``` ```
then
Then:
``` ```
pfctl -f /etc/pf.conf pfctl -f /etc/pf.conf
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
``` ```
Its not clear how to do rdr-to outgoing traffic. I could not make route-to scheme work. Its not clear how to do rdr-to outgoing traffic. I could not make route-to
rdr-to support is done using /dev/pf, that's why transparent mode requires root. scheme work. rdr-to support is done using /dev/pf, that's why transparent mode
requires root.
dvtws for all traffic: `dvtws` for all traffic:
/etc/pf.conf `/etc/pf.conf`:
``` ```
pass in quick on em0 proto tcp from port {80,443} 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 pass out quick on em0 proto tcp to port {80,443} divert-packet port 989
``` ```
then
Then:
``` ```
pfctl -f /etc/pf.conf pfctl -f /etc/pf.conf
./dvtws --port=989 --dpi-desync=split2 ./dvtws --port=989 --dpi-desync=split2
``` ```
dwtws only for table zapret with the exception of table nozapret : `dwtws` only for table zapret with the exception of table nozapret :
/etc/pf.conf `/etc/pf.conf`:
``` ```
set limit table-entries 2000000 set limit table-entries 2000000
table <zapret> file "/opt/zapret/ipset/zapret-ip.txt" table <zapret> file "/opt/zapret/ipset/zapret-ip.txt"
@ -312,119 +362,143 @@ pass out quick on em0 inet6 proto tcp to <zapret6> port {80,443} divert-packet
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} 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 pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-packet port 989 no state
``` ```
then
Then:
``` ```
pfctl -f /etc/pf.conf pfctl -f /etc/pf.conf
./dvtws --port=989 --dpi-desync=split2 ./dvtws --port=989 --dpi-desync=split2
``` ```
divert-packet automatically adds the reverse rule. By default also incoming traffic will be passwed to dvtws. divert-packet automatically adds the reverse rule. By default also incoming
This is highly undesired because it is waste of cpu resources and speed limiter. traffic will be passwed to `dvtws`. This is highly undesired because it is waste
The trick with "no state" and "in" rules allows to bypass auto reverse rule. 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. `dvtws` in OpenBSD sends all fakes through a divert socket because raw sockets
Looks like pf automatically prevent reinsertion of diverted frames. Loop problem does not exist. 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 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. 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` : `ipset` scripts do not reload PF by default. To enable reload specify command in
`/opt/zapret/config`:
``` ```
LISTS_RELOAD="pfctl -f /etc/pf.conf" LISTS_RELOAD="pfctl -f /etc/pf.conf"
``` ```
Newer pfctl versions can reload tables only : Newer `pfctl` versions can reload tables only:
``` ```
pfctl -Tl -f /etc/pf.conf 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 : 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 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. If some list files do not exist and have references in pf.conf it leads to
After configuration is done you can put ipset script : 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 crontab -e
``` ```
then write the line : `0 12 */2 * * /opt/zapret/ipset/get_config.sh`
Then write the line:
```
0 12 */2 * * /opt/zapret/ipset/get_config.sh
```
## MacOS ## 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. Initially, the kernel of this OS was based on BSD. That's why it is still BSD
As usual a mass commercial project priorities differ from their free counterparts. but a lot was modified by Apple. As usual a mass commercial project priorities
Apple guys do what they want. differ from their free counterparts. Apple guys do what they want. What
What everyone have updated long ago they keep old like a mammoth. But who cares ? everyone have updated long ago they keep old like a mammoth. But who cares?
MacOS used to have ipfw but it was removed later and replaced by PF. MacOS used to have ipfw but it was removed later and replaced by PF. It looks
It looks like divert sockets are internally replaced with raw. Its possible to request a divert socket like divert sockets are internally replaced with raw. Its possible to request a
but it behaves exactly as raw socket with all its BSD inherited + apple specific bugs and feature. divert socket but it behaves exactly as raw socket with all its BSD inherited +
The fact is that divert-packet in `/etc/pf.conf` does not work. pfctl binary does not contain the word `divert`. 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. `dvtws` does compile but is useless.
After some efforts tpws works. Apple has removed some important stuff from their newer SDKs (DIOCNATLOOK) making After some efforts `tpws` works. Apple has removed some important stuff from
them undocumented and unsupported. their newer SDKs (DIOCNATLOOK) making them undocumented and unsupported.
With important definitions copied from an older SDK it was possible to make 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. 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`. 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. 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 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. In MacOS redirection works both for passthrough and outgoing traffic. Outgoing
Because tpws is forced to run as root to avoid loop its necessary to exempt root from the redirection. redirection requires route-to rule. Because tpws is forced to run as root to
That's why DPI bypass will not work for local requests from root. 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. 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. "secured" addresses are designed to be permanent and not related to the MAC
address.
And they really are. Except for link-locals. 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. 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) Just change the system time to tomorrow and reboot. Link-locals will change.
Looks like its a kernel bug. Link locals should not change. Its useless and can be harmful. Cant use LL as a gateway. (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. The easiest solution is to disable "secured" addresses.
Outgoing connections prefer randomly generated temporary addressesas like in other systems. 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. Put the string `net.inet6.send.opmode=0` to `/etc/sysctl.conf`. If not present
- create it.
Then reboot the system. 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 If you dont like this solution you can assign an additional static ipv6 address
to your LAN interface and use it as the gateway 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. `tpws` transparent mode only for outgoing connections.
/etc/pf.conf `/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 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 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 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 } pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root }
``` ```
then
Then:
``` ```
pfctl -ef /etc/pf.conf 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 /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. `tpws` transparent mode for both passthrough and outgoing connections. en1 - LAN.
``` ```
ifconfig en1 | grep fe80 ifconfig en1 | grep fe80
inet6 fe80::bbbb:bbbb:bbbb:bbbb%en1 prefixlen 64 scopeid 0x8 inet6 fe80::bbbb:bbbb:bbbb:bbbb%en1 prefixlen 64 scopeid 0x8
``` ```
/etc/pf.conf
`/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 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 en1 inet6 proto tcp from any to any port {80,443} -> fe80::bbbb:bbbb:bbbb:bbbb port 988
@ -433,7 +507,8 @@ rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 9
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 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 } pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root }
``` ```
then
Then:
``` ```
pfctl -ef /etc/pf.conf 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 /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
@ -448,22 +523,28 @@ Build from source : `make -C /opt/zapret mac`
`install_easy.sh` supports MacOS `install_easy.sh` supports MacOS
Shipped precompiled binaries are built for 64-bit MacOS with `-mmacosx-version-min=10.8` option. Shipped precompiled binaries are built for 64-bit MacOS with
They should run on all supported MacOS versions. `-mmacosx-version-min=10.8` option. They should run on all supported MacOS
If no - its easy to build your own. Running `make` automatically installs developer tools. versions. If no - its easy to build your own. Running `make` automatically
installs developer tools.
!! **Internet sharing is not supported** !! **WARNING**:
**Internet sharing is not supported!**
Routing is supported but only manually configured through PF. Routing is supported but only manually configured through PF. If you enable
If you enable internet sharing tpws stops functioning. When you disable internet sharing you may lose web site access. internet sharing tpws stops functioning. When you disable internet sharing you
may lose web site access.
To fix : `pfctl -f /etc/pf.conf` To fix:
```
pfctl -f /etc/pf.conf
```
If you need internet sharing use tpws socks mode. If you need internet sharing use `tpws` socks mode.
launchd is used for autostart (`/Library/LaunchDaemons/zapret.plist`) `launchd` is used for autostart (`/Library/LaunchDaemons/zapret.plist`)
Control script : `/opt/zapret/init.d/macos/zapret` Control script: `/opt/zapret/init.d/macos/zapret`
The following commands fork with both tpws and firewall (if `INIT_APPLY_FW=1` in config) The following commands fork with both tpws and firewall (if `INIT_APPLY_FW=1` in config)
``` ```
@ -471,41 +552,50 @@ The following commands fork with both tpws and firewall (if `INIT_APPLY_FW=1` in
/opt/zapret/init.d/macos/zapret stop /opt/zapret/init.d/macos/zapret stop
/opt/zapret/init.d/macos/zapret restart /opt/zapret/init.d/macos/zapret restart
``` ```
Work with tpws only :
Work with `tpws` only:
``` ```
/opt/zapret/init.d/macos/zapret start-daemons /opt/zapret/init.d/macos/zapret start-daemons
/opt/zapret/init.d/macos/zapret stop-daemons /opt/zapret/init.d/macos/zapret stop-daemons
/opt/zapret/init.d/macos/zapret restart-daemons /opt/zapret/init.d/macos/zapret restart-daemons
``` ```
Work with PF only :
Work with PF only:
``` ```
/opt/zapret/init.d/macos/zapret start-fw /opt/zapret/init.d/macos/zapret start-fw
/opt/zapret/init.d/macos/zapret stop-fw /opt/zapret/init.d/macos/zapret stop-fw
/opt/zapret/init.d/macos/zapret restart-fw /opt/zapret/init.d/macos/zapret restart-fw
``` ```
Reloading PF tables :
Reloading PF tables:
``` ```
/opt/zapret/init.d/macos/zapret reload-fw-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 configures `LISTS_RELOAD` in the config so `ipset *.sh` scripts
Installer creates cron job for `ipset/get_config.sh`, as in OpenWRT. 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. start-fw script automatically patches `/etc/pf.conf` inserting there `zapret`
Auto patching requires pf.conf with apple anchors preserved. anchors. Auto patching requires pf.conf with apple anchors preserved. If your
If your `pf.conf` is highly customized and patching fails you will see the warning. Do not ignore it. `pf.conf` is highly customized and patching fails you will see the warning. Do
In that case you need to manually insert "zapret" anchors to your `pf.conf` (keeping the right rule type ordering) : 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" rdr-anchor "zapret"
anchor "zapret" anchor "zapret"
unistall_easy.sh unpatches pf.conf unistall_easy.sh unpatches pf.conf
``` ```
start-fw creates 3 anchor files in `/etc/pf.anchors` : zapret,zapret-v4,zapret-v6. start-fw creates 3 anchor files in `/etc/pf.anchors` :
zapret,zapret-v4,zapret-v6.
- Last 2 are referenced by anchor `zapret`. - Last 2 are referenced by anchor `zapret`.
- Tables `nozapret`,`nozapret6` belong to anchor `zapret`. - Tables `nozapret`,`nozapret6` belong to anchor `zapret`.
- Tables `zapret`,`zapret-user` belong to anchor `zapret-v4`. - Tables `zapret`,`zapret-user` belong to anchor `zapret-v4`.
- Tables `zapret6`,`apret6-user` belong to anchor `zapret-v6`. - 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`. If an ip version is disabled then corresponding anchor is empty and is not
Tables are only created for existing list files in the ipset directory. referenced from the anchor `zapret`. Tables are only created for existing list
files in the `ipset` directory.