diff --git a/docs/bsd.md b/docs/bsd.md new file mode 100644 index 0000000..927e5bf --- /dev/null +++ b/docs/bsd.md @@ -0,0 +1,703 @@ +# Настройка BSD-подобных систем + + +## Поддерживаемые версии +**FreeBSD** 11.x+ , **OpenBSD** 6.x+, частично **MacOS Sierra +** + +> [!CAUTION] +> На более старых может собираться, может не собираться, может работать или не +> работать. На **FreeBSD** 10 собирается и работает `dvtws`. С `tpws` есть +> проблемы из-за слишком старой версии компилятора clang. Вероятно, будет +> работать, если обновить компилятор. Возможна прикрутка к последним версиям +> pfsense без веб интерфейса в ручном режиме через консоль. + + +## Особенности BSD систем +### Отсутствие nfqueue +В **BSD** нет `nfqueue`. Похожий механизм - *divert sockets*. Из каталога +**nfq** под **BSD** собирается `dvtws` вместо `nfqws`. Он разделяет с `nfqws` +большую часть кода и почти совпадает по параметрам командной строки. + +### Типы Firewall +**FreeBSD** содержит 3 фаервола : **IPFilter**, **ipfw** и **Packet Filter (PF +в дальнейшем)**. **OpenBSD** содержит только **PF**. + +### Сборка +Под **FreeBSD** `tpws` и `dvtws` собираются через `make`. + +Под **OpenBSD**: +```sh +make bsd +``` + +Под **MacOS**: +```sh +make mac +``` + +**FreeBSD** make распознает *BSDmakefile*, **OpenBSD** и **MacOS** - нет. +Поэтому там используется отдельный *target* в *Makefile*. Сборка всех +исходников: +```sh +make -C /opt/zapret +``` + +### Divert сокеты +*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`. + +### Lookup Tables +Скрипты `ipset/*.sh` при наличии **ipfw** работают с *ipfw lookup tables*. Это +прямой аналог **ipset**. *lookup tables* не разделены на **v4** и **v6**. Они +могут содержать **v4** и **v6** адреса и подсети одновременно. Если **ipfw** +отсутствует, то действие зависит от переменной `LISTS_RELOAD` в *config*. Если +она задана, то выполняется команда из `LISTS_RELOAD`. В противном случае не +делается ничего. Если `LISTS_RELOAD=-`, то заполнение таблиц отключается даже +при наличии **ipfw**. + +### PF с файла +**PF** может загружать ip таблицы из файла. Чтобы использовать эту возможность +следует отключить сжатие gzip для листов через параметр файла *config* +`GZIP_LISTS=0`. + +### Отсутствие splice +**BSD** не содержит системного вызова splice. `tpws` работает через переброску +данных в *user mode* в оба конца. Это медленнее, но не критически. Управление +асинхронными сокетами в `tpws` основано на linux-specific механизме *epoll*. В +**BSD** для его эмуляции используется *epoll-shim* - прослойка для эмуляции +*epoll* на базе *kqueue*. + +### mdig, ip2net +mdig и ip2net полностью работоспособны в **BSD**. В них нет ничего +системо-зависимого. + + +## FreeBSD +### Подгрузка ipdivert +*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`: +```sh +$ ipfw -q -f flush +``` + +### Авто-восстановление правил ipfw и работа в фоне +В `/etc/rc.firewall.my` можно дописывать правила **ipfw**, чтобы они +восстанавливались после перезагрузки. Оттуда же можно запускать и демоны +zapret, добавив в параметры `--daemon`. Например так: +```sh +$ pkill ^dvtws$ +$ /opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2 +``` + +Для перезапуска фаервола и демонов достаточно будет сделать: +```sh +$ /etc/rc.d/ipfw restart +``` + +### tpws в прозрачном режиме +Краткая инструкция по запуску `tpws` в прозрачном режиме. + +> [!NOTE] +> Предполагается, что интерфейс **LAN** называется `em1`, **WAN** - `em0`. + +#### Весь трафик +```sh +$ 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 + +```sh +$ 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 +``` + +> [!NOTE] +> Таблицы zapret, nozapret, ipban создаются скриптами из ipset по аналогии с +> Linux. Обновление скриптов можно забить в `cron` под root: +> ```sh +> $ crontab -e +> ``` +> +> ``` +> <...> +> 0 12 */2 * * /opt/zapret/ipset/get_config.sh +> ``` + +> [!CAUTION] +> При использовании **ipfw** `tpws` не требует повышенных привилегий для +> реализации прозрачного режима. Однако, без рута невозможен бинд на порты +> <1024 и смена UID/GID. Без смены UID будет рекурсия, поэтому правила **ipfw** +> нужно создавать с учетом UID, под которым работает `tpws`. Переадресация на +> порты >=1024 может создать угрозу перехвата трафика непривилегированным +> процессом, если вдруг `tpws` не запущен. + + +### Запуск `dvtws` + +#### Весь трафик +```sh +$ 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 + +```sh +$ 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. Лимит на количество элементов таблиц задается так: + ```sh + $ 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 + ``` + + ```sh + $ /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** и использует фаервол **PF**, имеющий +проблемы с *divert*. К счастью, модули **ipfw** и **ipdivert** присутствуют в +поставке последних версий **pfsense**. Их можно подгрузить через `kldload`. + +#### Особенности +В некоторых более старых версиях **pfsense** требуется изменить порядок +фаерволов через `sysctl`, сделав **ipfw** первым. В более новых эти параметры +`sysctl` отсутствуют, но система работает как надо и без них. В некоторых +случаях фаервол **PF** может ограничивать возможности `dvtws`, в частности в +области фрагментации ip. + +#### Исполняемые файлы +Присутствуют по умолчанию правила scrub для реассемблинга фрагментов. +Бинарики из [`binaries/freebsd-x64`](../binaries/freebsd-x64) собраны под +**FreeBSD 11**. Они должны работать и на последующих версиях **FreeBSD**, +включая **pfsense**. Можно пользоваться `install_bin.sh`. + +#### Автозапуск +Пример скрипта автозапуска лежит в [`init.d/pfsense`](../init.d/pfsense). Его +следует поместить в `/usr/local/etc/rc.d` и отредактировать на предмет правил +**ipfw** и запуска демонов. Есть встроенный редактор `edit` как более +приемлемая альтернатива `vi`. + +> [!NOTE] +> Поскольку `git` отсутствует, копировать файлы удобнее всего через `ssh`. +> `curl` присутствует по умолчанию. Можно скопировать zip с файлами zapret и +> распаковать в `/opt`, как это делается на других системах. Тогда `dvtws` +> нужно запускать как `/opt/zapret/nfq/dvtws`. Либо скопировать только `dvtws` +> в `/usr/local/sbin`. Как вам больше нравится. + +> [!NOTE] +> Скрипты ipset работают, крон есть. Можно сделать автообновление листов. + +> [!NOTE] +> Если вас напрягает бедность имеющегося репозитория, можно включить +> репозиторий от **FreeBSD**, который по умолчанию выключен. +> +> Поменяйте *no* на *yes* в `/usr/local/etc/pkg/repos/FreeBSD.conf` +> +> Можно установить весь привычный софт, включая `git`, чтобы напрямую скачивать +> zapret с github. + +- `/usr/local/etc/rc.d/zapret.sh` (chmod `755`): +```sh +#!/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 +Что касается `tpws`, то видимо имеется некоторый конфликт двух фаерволов, и +правила fwd в **ipfw** не работают. Работает перенаправление средствами **PF** +как описано в разделе по **FreeBSD**. В **PF** можно изменять правила только +целыми блоками - якорями (anchors). Нельзя просто так добавить или удалить +что-то. Но чтобы какой-то anchor был обработан, на него должна быть ссылка из +основного набора правил. Его трогать нельзя, иначе порушится весь фаервол. +Поэтому придется править код скриптов pfsense. + +1. Поправьте `/etc/inc/filter.inc` следующим образом: +``` + <...> + /* MOD */ + $natrules .= "# ZAPRET redirection\n"; + $natrules .= "rdr-anchor \"zapret\"\n"; + + $natrules .= "# TFTP proxy\n"; + $natrules .= "rdr-anchor \"tftp-proxy/*\"\n"; + <...> +``` + +2. Напишите файл с содержимым 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** не нужен. + +3. Добавьте в автозапуск `/usr/local/etc/rc.d/zapret.sh`: +```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 +``` + +4. После перезагрузки проверьте, что правила создались: +```sh +$ 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 + +$ 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 +``` + +> [!NOTE] +> Так же есть более элегантный способ запуска `tpws` через @reboot в `cron` и +> правило перенаправления в UI. Это позволит не редактировать код pfsense. + + +## OpenBSD + +### tpws бинд на ipv4 +В `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 +``` + +```sh +$ pfctl -f /etc/pf.conf +$ tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 +``` + +> [!NOTE] +> В **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 +``` + +```sh +$ pfctl -f /etc/pf.conf +$ ./dvtws --port=989 --dpi-desync=split2 +``` + +#### Трафик только на таблицу zapret +> За исключением таблицы nozapret + +- `/etc/pf.conf`: +``` +set limit table-entries 2000000 +table file "/opt/zapret/ipset/zapret-ip.txt" +table file "/opt/zapret/ipset/zapret-ip-user.txt" +table file "/opt/zapret/ipset/zapret-ip-exclude.txt" +pass out quick on em0 inet proto tcp to port {80,443} +pass in quick on em0 inet proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state +pass in quick on em0 inet proto tcp from port {80,443} no state +pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state +table file "/opt/zapret/ipset/zapret-ip6.txt" +table file "/opt/zapret/ipset/zapret-ip-user6.txt" +table file "/opt/zapret/ipset/zapret-ip-exclude6.txt" +pass out quick on em0 inet6 proto tcp to port {80,443} +pass in quick on em0 inet6 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state +pass in quick on em0 inet6 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state +pass in quick on em0 inet6 proto tcp from port {80,443} no state +pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state +``` + +```sh +$ pfctl -f /etc/pf.conf +$ ./dvtws --port=989 --dpi-desync=split2 +``` + + +### Проблемы с badsum +**OpenBSD** принудительно пересчитывает tcp checksum после divert, поэтому +скорее всего `dpi-desync-fooling=badsum` у вас не заработает. При использовании +этого параметра `dvtws` предупредит о возможной проблеме. + + +### Особенность отправки fake пакетов +В **OpenBSD** `dvtws` все фейки отсылает через divert socket, поскольку эта +возможность через raw sockets заблокирована. Видимо **PF** автоматически +предотвращает повторный заворот diverted фреймов, поэтому проблемы зацикливания +нет. + + +### Возможная оптимизация трафика +divert-packet автоматически вносит обратное правило для перенаправления. Трюк с +no state и in правилом позволяет обойти эту проблему, чтобы напрасно не гнать +массивный трафик через `dvtws`. + + +### Перезагрузка PF таблиц +Скрипты из **ipset** не перезагружают таблицы в **PF** по умолчанию. + +Чтобы они это делали, добавьте параметр в `/opt/zapret/config`: +``` +LISTS_RELOAD="pfctl -f /etc/pf.conf" +``` + +Более новые версии `pfctl` понимают команду перезагрузить только таблицы: +> [!NOTE] +> Но это не относится к **OpenBSD 6.8**. В новых **FreeBSD** есть. +```sh +$ pfctl -Tl -f /etc/pf.conf +``` + +> [!IMPORTANT] +> Не забудьте выключить сжатие gzip: `GZIP_LISTS=0` + +> [!IMPORTANT] +> Если в вашей конфигурации какого-то файла листа нет, то его необходимо +> исключить из правил PF. Если вдруг листа нет, и он задан в pf.conf, будет +> ошибка перезагрузки фаервола. + +> [!NOTE] +> После настройки обновление листов можно поместить в `cron`: +> ```sh +> $ crontab -e +> ``` +> +> ``` +> <...> +> 0 12 */2 * * /opt/zapret/ipset/get_config.sh +> ``` + + +## MacOS +### Введение +Иначально ядро этой ОС "darwin" основывалось на **BSD**, потому в ней много +похожего на другие версии **BSD**. Однако, как и в других массовых коммерческих +проектах, приоритеты смещаются в сторону от оригинала. Яблочники что хотят, то +и творят. + + +### dvtws бесполезен +Раньше был **ipfw**, потом его убрали, заменили на **PF**. Есть сомнения, что +*divert сокеты* в ядре остались. Попытка создать *divert socket* не выдает +ошибок, но полученный сокет ведет себя точно так же, как *raw*, со всеми его +унаследованными косяками + еще яблочно специфическими. В **PF** *divert-packet* +не работает. Простой grep бинарика `pfctl` показывает, что там нет слова +"divert", а в других версиях **BSD** оно есть. `dvtws` собирается, но +совершенно бесполезен. + + +### tpws +`tpws` удалось адаптировать, он работоспособен. Получение адреса назначения для +прозрачного прокси в **PF** (`DIOCNATLOOK`) убрали из заголовков в новых SDK, +сделав фактически недокументированным. + +В `tpws` перенесены некоторые определения из более старых версий яблочных SDK. +С ними удалось завести прозрачный режим. Однако, что будет в следующих версиях +угадать сложно. Гарантий нет. Еще одной особенностью **PF** в **MacOS** +является проверка на рута в момент обращения к `/dev/pf`, чего нет в остальных +**BSD**. `tpws` по умолчанию сбрасывает рутовые привилегии. Необходимо явно +указать параметр `--user=root`. В остальном **PF** себя ведет похоже на +**FreeBSD**. Синтаксис `pf.conf` тот же. + +> [!IMPORTANT] +> На **MacOS** работает редирект как с проходящего трафика, так и с локальной +> системы через route-to. Поскольку `tpws` вынужден работать под root, для +> исключения рекурсии приходится пускать исходящий от root трафик напрямую. +> Отсюда имеем недостаток - **обход DPI для рута работать НЕ будет**. + +#### Работа в прозрачном режиме только для исходящих запросов +- `/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 } +``` + +```sh +$ 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 +``` + +#### Работа в прозрачном режиме +> [!NOTE] +> Предполагается, что имя LAN интерфейса - `en1` + +```sh +$ 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 } +``` + +```sh +$ 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 +``` + + +### Проблема link-local адреса +Если вы пользуетесь **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**. Он добавится к автоматически настраеваемым. + + +### Сборка +```sh +$ make -C /opt/zapret mac +``` + +> [!IMPORTANT] +> Скрипты получения листов ipset/*.sh работают. Если будете пользоваться +> `ipset/get_combined.sh`, нужно установить `GNU grep` через `brew`. Имеющийся +> очень старый и безумно медленный с оцией `-f`. + + +### Простая установка +В **MacOS** поддерживается `install_easy.sh` + +В комплекте идут бинарики, собраные под 64-bit с опцией +`-mmacosx-version-min=10.8`. Они должны работать на всех поддерживаемых версиях +**MacOS**. Если вдруг не работают - можно собрать свои. Developer tools +ставятся автоматом при запуске `make`. + +> [!WARNING] +> Internet sharing средствами системы **не поддерживается**! +> +> Поддерживается только роутер, настроенный своими силами через **PF**. Если вы +> вдруг включили шаринг, а потом выключили, то доступ к сайтам может пропасть +> совсем. +> +> Лечение: +> ```sh +> $ pfctl -f /etc/pf.conf +> ``` +> +> Если вам нужен шаринг интернета, лучше отказаться от прозрачного режима и +> использовать socks прокси. + +Для автостарта используется **launchd** (`/Library/LaunchDaemons/zapret.plist`) +Управляющий скрипт : `/opt/zapret/init.d/macos/zapret` + +Следующие команды работают с `tpws` и фаерволом одновременно (если +`INIT_APPLY_FW=1` в config) + +```sh +$ /opt/zapret/init.d/macos/zapret start +$ /opt/zapret/init.d/macos/zapret stop +$ /opt/zapret/init.d/macos/zapret restart +``` + +Работа только с tpws: +```sh +$ /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: +```sh +$ /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 таблиц из файлов: +```sh +$ /opt/zapret/init.d/macos/zapret reload-fw-tables +``` + +> [!NOTE] +> Инсталятор настраивает `LISTS_RELOAD` в config, так что скрипты +> [`ipset/*.sh`](../ipset/) автоматически перезагружают IP таблицы в PF. + +> [!NOTE] +> Автоматически создается 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" +``` + +> [!NOTE] +> При деинсталяции через `uninstall_easy.sh` модификации `pf.conf` убираются. + +> [!NOTE] +> start-fw создает 3 файла anchors в `/etc/pf.anchors`: `zapret`, `zapret-v4`, +> `zapret-v6`. Последние 2 подключаются из anchor "zapret". + +> [!NOTE] +> Таблицы `nozapret` и `nozapret6` принадлежат anchor "zapret". +> +> Таблицы `zapret` и `zapret-user` в anchor "zapret-v4". +> +> Таблицы `zapret6` и `zapret6-user` в anchor "zapret-v6". +> +> Если какая-то версия протокола отключена - соответствующий anchor пустой и не +> упоминается в anchor "zapret". Таблицы и правила создаются только на те +> листы, которые фактически есть в директории ipset. + + +### Вариант 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м. пример [в файле](../init.d/macos/custom.d.examples/50-extra-tpws) diff --git a/docs/bsd.txt b/docs/bsd.txt deleted file mode 100644 index 829dc5c..0000000 --- a/docs/bsd.txt +++ /dev/null @@ -1,476 +0,0 @@ -Поддерживаемые версии ---------------------- - -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 file "/opt/zapret/ipset/zapret-ip.txt" -table file "/opt/zapret/ipset/zapret-ip-user.txt" -table file "/opt/zapret/ipset/zapret-ip-exclude.txt" -pass out quick on em0 inet proto tcp to port {80,443} -pass in quick on em0 inet proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state -pass in quick on em0 inet proto tcp from port {80,443} no state -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state -pass in quick on em0 inet proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state -pass in quick on em0 inet proto tcp from port {80,443} no state -pass out quick on em0 inet proto tcp to port {80,443} divert-packet port 989 no state -table file "/opt/zapret/ipset/zapret-ip6.txt" -table file "/opt/zapret/ipset/zapret-ip-user6.txt" -table file "/opt/zapret/ipset/zapret-ip-exclude6.txt" -pass out quick on em0 inet6 proto tcp to port {80,443} -pass in quick on em0 inet6 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state -pass in quick on em0 inet6 proto tcp from port {80,443} no state -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state -pass in quick on em0 inet6 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state -pass in quick on em0 inet6 proto tcp from port {80,443} no state -pass out quick on em0 inet6 proto tcp to port {80,443} divert-packet port 989 no state ------------- -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