Установка программы модификации сетевых пакетов NFQWS на роутер Keenetiс

Сегодня рассмотрим вариант установки утилиты модификации сетевых пакетов Zapret на роутеры Keenetic. В отличии от простого использования на конкретных устройствах, при установке на роутер появляется возможность обрабатывать трафик идущий от всех устройств, подключенных к домашней локальной сети (ПК, смартфоны и смарт телевизоры).

Указанная утилита предлагает два основных режима работы — это TPWS или NFQWS. При использовании в режиме TPWS есть недостатки, заключающиеся в том, что в этом режиме не модифицируется протокол QUIC (HTTP/3), а также приложение YouTube на смарт телевизорах с WebOS или Android TV перестает вообще запускаться.

Для начала попробуем определиться с тем, какие протоколы используются YouTube на различных устройствах:

В качестве вариантов решения данной проблемы при использовании утилиты в режиме TPWS, я вижу три возможных варианта:

Я пошел другим более гибким и правильным путем, использования утилиты zapret в режиме NFQWS. Этот режим имеет ряд преимуществ пред режимом TPWS — больше параметров модификации сетевых пакетов, а также возможность модификации трафика по протоколу QUIC.

Данная инструкция будет выполнятся на примере роутера Keenetic ultra (kn-1810).

После развертывания Entware на роутере с помощью терминальной программы Putty создаем SSH подключения, с указанием IP-адрес роутера (по умолчанию 192.168.1.1) и порта 222. Дальше авторизуемся с использованием логина: root и пароля: keenetic.

Далее можно приступать непосредственно к установке утилиты NFQWS:

opkg install coreutils-sort curl git-http grep gzip ipset iptables kmod_ndms xtables-addons_legacy

Приходим папку opt:

cd /opt/

Скачиваем Zapret с github:

git clone --depth=1 https://github.com/bol-van/zapret.git

Для начала узнаем имя внешнего сетевого интерфейса (WAN) на роутере. Его можно узнать воспользовавшись командой ifconfig, которая выведет все сетевые интерфейсы в системе. Просто находим тот интерфейс, у которого будет ваш внешний IP адрес. В моем случаи — это eth3.

Переходим в папку zapret и выполняем скрипт:

cd zapret
./install_easy.sh

Далее делаем отвечаем на все вопросы, как скриншоте:

Выполнение скрипта install_easy.sh

Выполнение скрипта install_easy.sh

Выбираем свой ранее найденное имя внешнего сетевого интерфейса (WAN):

Выбираем имя внешнего сетевого интерфейса (WAN)

Выбираем имя внешнего сетевого интерфейса (WAN)

Продолжаем отвечать на все вопросы:

Завершение выполнения скрипта install_easy.sh

Завершение выполнения скрипта install_easy.sh

Правим скрипт c именем zapret в командной строке с помощью предпочитаемого текстового редактора (в качестве примера vi) или можно зайти с компьютера через сеть на USB-накопитель (если он расшарен с помощью сервера SMB) и редактировать в текстовом редакторе на компьютере:

vi /opt/zapret/init.d/sysv/zapret

Добавляем в функцию do_start () код загрузки модулей ядра linux (xt_multiport.ko, xt_connbytes.ko, xt_NFQUEUE.ko), так как они по умолчанию не загружаются, а без них iptables будет выдавать ошибки при попытке приметь необходимые правила.

Для перенаправления исходящего и проходящего в сторону внешнего интерфейса трафика на очередь NFQUEUE, в функцию do_start() и do_stop() закомментируем строчки с вызовами zapret_apply_firewall в zapret_unapply_firewall и туда же добавляем свои правила iptables. В данных командах необходимо заменить название внешнего интернет интерфейса (WAN) eth3 на свой.

Затем в секции restart-fw|restart_fw закомментируем строчки с вызовами zapret_apply_firewall в zapret_unapply_firewall и туда же добавляем те же правила iptables, что уже писали выше, но в обратном порядке.

#!/bin/sh
### BEGIN INIT INFO
# Provides:		zapret
# Required-Start:	$local_fs $network
# Required-Stop:	$local_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
### END INIT INFO

SCRIPT=$(readlink -f "$0")
EXEDIR=$(dirname "$SCRIPT")
ZAPRET_BASE=$(readlink -f "$EXEDIR/../..")
. "$EXEDIR/functions"

NAME=zapret
DESC=anti-zapret

do_start()
{

    if lsmod | grep "xt_multiport " &> /dev/null ;  then
		echo "xt_multiport.ko is already loaded"
    else
        if insmod /lib/modules/$(uname -r)/xt_multiport.ko &> /dev/null; then
			echo "iptable_raw.ko loaded"
        else
			echo "Cannot find xt_multiport.ko kernel module, aborting"
			exit 1
        fi
	fi
     
	if lsmod | grep "xt_connbytes " &> /dev/null ;  then
        echo "xt_connbytes.ko is already loaded"
    else
        if insmod /lib/modules/$(uname -r)/xt_connbytes.ko &> /dev/null; then
			echo "xt_connbytes.ko loaded"
        else
			echo "Cannot find xt_connbytes.ko kernel module, aborting"
			exit 1
        fi
	fi
	
	if lsmod | grep "xt_NFQUEUE " &> /dev/null ;  then
        echo "xt_NFQUEUE.ko is already loaded"
    else
        if insmod /lib/modules/$(uname -r)/xt_NFQUEUE.ko &> /dev/null; then
            echo "xt_NFQUEUE.ko loaded"
        else
            echo "Cannot find xt_NFQUEUE.ko kernel module, aborting"
            exit 1
        fi
    fi		 

	zapret_run_daemons
	#[ "$INIT_APPLY_FW" != "1" ] || { zapret_apply_firewall; }
    iptables -t mangle -I POSTROUTING -o eth3 -p tcp --dport 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 -o eth3 -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
	iptables -t mangle -I POSTROUTING -o eth3 -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 210 --queue-bypass
	iptables -t nat -A POSTROUTING -o eth3 -j MASQUERADE

}
do_stop()
{
	zapret_stop_daemons
#	[ "$INIT_APPLY_FW" != "1" ] || zapret_unapply_firewall
	iptables -t mangle -D POSTROUTING -o eth3 -p tcp --dport 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 -D POSTROUTING -o eth3 -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
	iptables -t mangle -D POSTROUTING -o eth3 -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 210 --queue-bypass
	iptables -t nat -D POSTROUTING -o eth3 -j MASQUERADE
}

case "$1" in
	start)
		do_start
		;;

	stop)
		do_stop
		;;

	restart)
		do_stop
		do_start
		;;

	start-fw|start_fw)
		zapret_apply_firewall
		;;
	stop-fw|stop_fw)
		zapret_unapply_firewall
		;;

	restart-fw|restart_fw)
		#	zapret_unapply_firewall
	#	zapret_apply_firewall
	iptables -t mangle -D POSTROUTING -o eth3 -p tcp --dport 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 -D POSTROUTING -o eth3 -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
	iptables -t mangle -D POSTROUTING -o eth3 -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 210 --queue-bypass
	iptables -t nat -D POSTROUTING -o eth3 -j MASQUERADE	
	
	iptables -t mangle -I POSTROUTING -o eth3 -p tcp --dport 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 -o eth3 -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
	iptables -t mangle -I POSTROUTING -o eth3 -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 210 --queue-bypass
	iptables -t nat -A POSTROUTING -o eth3 -j MASQUERADE
		;;
	
	start-daemons|start_daemons)
		zapret_run_daemons
		;;
	stop-daemons|stop_daemons)
		zapret_stop_daemons
		;;
	restart-daemons|restart_daemons)
		zapret_stop_daemons
		zapret_run_daemons
		;;

	reload-ifsets|reload_ifsets)	
		zapret_reload_ifsets
		;;
	list-ifsets|list_ifsets)	
		zapret_list_ifsets
		;;
	list-table|list_table)	
		zapret_list_table
		;;
		
  *)
	N=/etc/init.d/$NAME
	echo "Usage: $N {start|stop|restart|start-fw|stop-fw|restart-fw|start-daemons|stop-daemons|restart-daemons|reload-ifsets|list-ifsets|list-table}" >&2
	exit 1
	;;
esac

exit 0

Все на этом правка скрипта zapret закончена, сохраняем и выходим из текстового редактора.

В качестве небольшого пояснения по данным правилам iptables:

Команда перенаправляет весь исходящий и проходящий в сторону внешнего интерфейса eth3 трафик HTTP (TCP порт 80) на очередь NFQUEUE №200:

iptables -t mangle -I POSTROUTING -o eth3 -p tcp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass

Команда перенаправляет весь исходящий и проходящий в сторону внешнего интерфейса eth3 трафик HTTPS (TCP порт 443) на очередь NFQUEUE №200:

iptables -t mangle -I POSTROUTING -o eth3 -p tcp --dport 80 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass

Команда перенаправляет весь исходящий и проходящий в сторону внешнего интерфейса eth3 трафик QUIC (UDP порт 443) на очередь NFQUEUE №210:

 iptables -t mangle -I POSTROUTING -o eth3 -p udp --dport 443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 210 --queue-bypass

Также согласно комментарию автора данной утилиты для успешной работы с протоком QUIC через NFQWS на роутера Keenetic необходимо добавить маскарад на исходящий интерфейс WAN:

iptables -t nat -A POSTROUTING -o eth3 -j MASQUERADE

Данные правила представлены для случая использования протокола IPv4, а в случаи также использования протокола IPv6 необходимо добавлять аналогичные правила, но с использованием команды ip6tables.

При запуске скрипта zapret в режиме поддержки протокола QUIC будут подыматься два отдельных процесса NFQWS, первый будет обрабатывать трафик по протоколам HTTP и HTTPS на очереди NFQUEUE №200, а второй трафик протокола QUIC на очереди NFQUEUE №210.

После сохранения файла zapret делаем ссылку на скрипт zapret в автозагрузку:

ln -fs /opt/zapret/init.d/sysv/zapret /opt/etc/init.d/S90-zapret

Далее необходимо создать скрип, чтобы брандмауэр netfilter не забывал настроенные выше правила (иначе система быстро перезапишет наши правила). Делаем это также в командной строке с помощью текстового редактора:

vi /opt/etc/ndm/netfilter.d/000-zapret.sh

Вставляем в файл следующий код:

#!/bin/sh
[ "$type" == "ip6tables" ] && exit 0
[ "$table" != "mangle" ] && exit 0
/opt/zapret/init.d/sysv/zapret restart-fw 

И даем право на исполнения скрипту 000-zapret.sh с помощью команды:

chmod +x /opt/etc/ndm/netfilter.d/000-zapret.sh

Данный скрип будет вызывать наш ранее правленый скрипт zapretс параметром restart-fw, где мы прописалиправила iptables.

Аналогично создаем скрипт отключения проверки контрольной суммы пакетов:

vi /opt/etc/init.d/S00fix

Вставляем в файл следующий код:

#!/bin/sh
start() {
    echo 0 > /proc/sys/net/netfilter/nf_conntrack_checksum
}
stop() {
    echo 1 > /proc/sys/net/netfilter/nf_conntrack_checksum
}
case "$1" in
    'start')
        start
        ;;
    'stop')
        stop
        ;;
    *)
        stop
        start
        ;;
esac
exit 0

Также не забываем дать права на исполнения данному скрипту:

chmod +x /opt/etc/init.d/S00fix

И теперь в конце настроим конфиг NFQWS, находящийся по пути /opt/zapret/config.

В командной строке с помощью текстового редактора или лучше с компьютера через сеть редактируем:

vi /opt/zapret/config

Необходимо внести следующие правки:

Раскомментировать строчку

WS_USER=nobody

Для включения режима модификации NFQWS трафика протокола QUIC изменить MODE_QUIC на:

MODE_QUIC=1

Далее необходимо прописать параметры для запуска процессов NFQWS. Тут нужно подбирать под себя, какие параметры дадут нужный результат.

В моем случаи для протоколов HTTP и HTTPS (с данными параметрами будет запущен первый процесс NFQWS):

NFQWS_OPT_DESYNC="--dpi-desync=fake,disorder2 --dpi-desync-split-pos=1 --dpi-desync-ttl=6 --dpi-desync-fooling=badsum --dpi-desync-repeats=6 --dpi-desync-any-protocol --dpi-desync-cutoff=d4"

И для протокола QUIC (с данными параметрами будет запущен второй процесс NFQWS):

NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake,disorder2 --dpi-desync-repeats=6 --dpi-desync-any-protocol --dpi-desync-cutoff=d4"

Мой готовый конфиг:

# this file is included from init scripts
# change values here

# can help in case /tmp has not enough space
#TMPDIR=/opt/zapret/tmp

# redefine user for zapret daemons. required on Keenetic
WS_USER=nobody

# override firewall type : iptables,nftables,ipfw
FWTYPE=iptables

# options for ipsets
# maximum number of elements in sets. also used for nft sets
SET_MAXELEM=522288
# too low hashsize can cause memory allocation errors on low RAM systems , even if RAM is enough
# too large hashsize will waste lots of RAM
IPSET_OPT="hashsize 262144 maxelem $SET_MAXELEM"
# dynamically generate additional ip. $1 = ipset/nfset/table name
#IPSET_HOOK="/etc/zapret.ipset.hook"

# options for ip2net. "-4" or "-6" auto added by ipset create script
IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4"
IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5"
# options for auto hostlist
AUTOHOSTLIST_RETRANS_THRESHOLD=3
AUTOHOSTLIST_FAIL_THRESHOLD=3
AUTOHOSTLIST_FAIL_TIME=60
# 1 = debug autohostlist positives to ipset/zapret-hosts-auto-debug.log
AUTOHOSTLIST_DEBUGLOG=0

# number of parallel threads for domain list resolves
MDIG_THREADS=30

# ipset/*.sh can compress large lists
GZIP_LISTS=1
# command to reload ip/host lists after update
# comment or leave empty for auto backend selection : ipset or ipfw if present
# on BSD systems with PF no auto reloading happens. you must provide your own command
# set to "-" to disable reload
#LISTS_RELOAD="pfctl -f /etc/pf.conf"

# override ports
#HTTP_PORTS=80-81,85
#HTTPS_PORTS=443,500-501
#QUIC_PORTS=443,444

# CHOOSE OPERATION MODE
# MODE : nfqws,tpws,tpws-socks,filter,custom
# nfqws : nfqws for dpi desync
# tpws : tpws transparent mode
# tpws-socks : tpws socks mode
# filter : no daemon, just create ipset or download hostlist
# custom : custom mode. should modify custom init script and add your own code
MODE=nfqws
# apply fooling to http
MODE_HTTP=1
# for nfqws only. support http keep alives. enable only if DPI checks for http request in any outgoing packet
MODE_HTTP_KEEPALIVE=0
# apply fooling to https
MODE_HTTPS=1
# apply fooling to quic
MODE_QUIC=1
# none,ipset,hostlist,autohostlist
MODE_FILTER=ipset

# CHOOSE NFQWS DAEMON OPTIONS for DPI desync mode. run "nfq/nfqws --help" for option list
DESYNC_MARK=0x40000000
DESYNC_MARK_POSTNAT=0x20000000
NFQWS_OPT_DESYNC="--dpi-desync=fake,disorder2 --dpi-desync-split-pos=1 --dpi-desync-ttl=6 --dpi-desync-fooling=badsum --dpi-desync-repeats=6 --dpi-desync-any-protocol --dpi-desync-cutoff=d4" 
#NFQWS_OPT_DESYNC_HTTP=
#NFQWS_OPT_DESYNC_HTTPS=
#NFQWS_OPT_DESYNC_HTTP6=
#NFQWS_OPT_DESYNC_HTTPS6=
NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake,disorder2 --dpi-desync-repeats=6 --dpi-desync-any-protocol --dpi-desync-cutoff=d4"
#NFQWS_OPT_DESYNC_QUIC6=

# CHOOSE TPWS DAEMON OPTIONS. run "tpws/tpws --help" for option list
TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3 --oob"

# openwrt only : donttouch,none,software,hardware
FLOWOFFLOAD=donttouch

# openwrt: specify networks to be treated as LAN. default is "lan"
#OPENWRT_LAN="lan lan2 lan3"
# openwrt: specify networks to be treated as WAN. default wans are interfaces with default route
#OPENWRT_WAN4="wan vpn"
#OPENWRT_WAN6="wan6 vpn6"

# for routers based on desktop linux and macos. has no effect in openwrt.
# CHOOSE LAN and optinally WAN/WAN6 NETWORK INTERFACES
# or leave them commented if its not router
# it's possible to specify multiple interfaces like this : IFACE_LAN="eth0 eth1 eth2"
# if IFACE_WAN6 is not defined it take the value of IFACE_WAN
IFACE_LAN=br0
IFACE_WAN=eth3
#IFACE_WAN6="ipsec0 wireguard0 he_net"

# should start/stop command of init scripts apply firewall rules ?
# not applicable to openwrt with firewall3+iptables
INIT_APPLY_FW=1
# firewall apply hooks
#INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up"
#INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up"
#INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down"
#INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down"

# do not work with ipv4
#DISABLE_IPV4=1
# do not work with ipv6
DISABLE_IPV6=0

# select which init script will be used to get ip or host list
# possible values : get_user.sh get_antizapret.sh get_combined.sh get_reestr.sh get_hostlist.sh
# comment if not required
GETLIST=get_user.sh

На этом настройка роутера завершена и можно запускать в работу NFQWS и проверять работоспособность с помощью команды:

/opt/zapret/init.d/sysv/zapret start

Для перезагрузки NFQWS использовать команду:

/opt/zapret/init.d/sysv/zapret restart

Для остановки NFQWS использовать команду:

/opt/zapret/init.d/sysv/zapret stop

Также в случаи, если есть проблема доступам к сайтам по доменным именам необходимо заменить в настройках роутера DNS-серверы провайдера на публичные. Прописываем IP адреса DNS — 8.8.8.8 и 8.8.4.4, и не забываем поставить галочку игнорировать DNS предлагаемые провайдером интернета:

Настройки роутера для работы с публичными DNS-серверами

Настройки роутера для работы с публичными DNS-серверами

В случаи проблем с доступностью или скоростью доступа к некоторым сайтом меняем параметры в NFQWS_OPT_DESYNC_QUIC и/или NFQWS_OPT_DESYNC, перезагружаем утилиту NFQWS с помощью команды и опять проверяем, и так делаем по циклу пока не получим нужный результат.

© Habrahabr.ru