bol-van / zapret

DPI bypass multi platform
8.16k stars 620 forks source link

zapret along with jool #174

Closed maxpain closed 8 months ago

maxpain commented 8 months ago

Я пытаюсь заставить работать zapret вместе с Jool (NAT64 gateway) в kernel mode, но не понимаю как нужно настраивать tpws. IPv6 пакеты от wireguard клиентов приходят на VM, которая трансформирует эти пакеты в IPv4, и после этого должен отрабатывать tpws.

Мне нужно включать поддержку IPv6 в tpws или нет? Что лучше использовать, nftables или iptables?

bol-van commented 8 months ago

tpws цепляется на prerouting, поэтому он перехватывает поток на этапе вхождения на систему он не может перехватывать на этапе ухода из системы если на вход идет ipv6, значит и перехватывать тоже надо ipv6. tpws не меняет адрес назначения, потому он будет эманировать аналогичный tcp поток от себя. следовательно, нужно сделать так, чтобы ваш jool корректно работал не только на входящий, но и на генерируемый на этой же системе трафик. может он это или нет - я не знаю. если с этим будут проблемы, лучше использовать nfqws. он цепляется как раз на уходящий трафик

bol-van commented 8 months ago

на счет ip/nftables - как удобнее. nftables имеет больше возможностей если Jool какой-то очень хитрый драйвер и хватает пакеты очень рано в цепочке netfilter (типа таблицы raw), то в nft всегда можно поставить приоритет еще ниже, чтобы он хватал ДО. в iptables приоритеты не изменить для iptables самое раннее - это -t raw PREROUTING. он выполняется еще до conntrack

maxpain commented 8 months ago

Jool делает NAT64 трансляцию только если пакет форвардится.

https://nicmx.github.io/Jool/en/faq.html#why-is-my-ping-not-working

Why is my ping not working? Probably because you started the ping on the same machine (or rather, network namespace) your translator instance is attached to.

At present, Netfilter Jool only hooks itself to PRE_ROUTING. It does not attach itself to LOCAL_OUT. This means it can only translate traffic that inbounds from some interface (physical or otherwise). It does not intercept packets sourced from its own network namespace.

Because iptables provides matching functionality, it makes more sense to attach iptables Jool instances to LOCAL_OUT. And AFAIK, there’s nothing stopping you from doing so. But don’t quote me; I haven’t tested it.

bol-van commented 8 months ago

Тогда смотрите в сторону построения роутера на базе виртуальных интерфейсов. Их великое множество. Выбирайте, используйте ip rule, таблицы маршрутизации. Возможно, netns. Суть такая, что

IPV6 -> ETH0 -> NAT64 -> VETH -> ETH1 -> IPV4 Перехват ipv4 на этапе veth

maxpain commented 8 months ago

Хм, было бы идеально обойтись без отдельного netspace. Настроил по вашему совету nfqws, который вешается на POSTROUTING, а Jool настроил в iptables режиме (до этого работал в netfilter режиме, и, кстати, nftables не поддерживает)

iptables -t mangle -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-A PREROUTING -j JOOL --instance nat64
-A POSTROUTING -o ens3 -p tcp -m multiport --dports 443 -m connbytes --connbytes 1:6 --connbytes-mode packets --connbytes-dir original -m mark ! --mark 0x40000000/0x40000000 -m set ! --match-set nozapret dst -j NFQUEUE --queue-num 201 --queue-bypass
-A POSTROUTING -o ens3 -p tcp -m multiport --dports 80 -m connbytes --connbytes 1:6 --connbytes-mode packets --connbytes-dir original -m mark ! --mark 0x40000000/0x40000000 -m set ! --match-set nozapret dst -j NFQUEUE --queue-num 200 --queue-bypass

(в ip6tables всё аналогично)

По логике всё должно работать, но приходящие из wg пакеты обрабатываются только Jool'ом, а nfqws их не трогает, странно.

Если дергать заблокированный сайт с самой VM — то всё ок, обход DPI работает.

maxpain commented 8 months ago

Решил добавить лог после Jool и до nfqws, обнаружил что логирование срабатывает пока не добавлю к нему фильтр -m connbytes --connbytes 1:6 --connbytes-mode packets --connbytes-dir original, соответственно из-за этого фильтра трафик, обработанный Jool, не обрабатывается nfqws

bol-van commented 8 months ago

Это может говорить о том, что пакет не проходит conntrack вообще Может там в -t raw написано NOTRACK ?

virtual router только кажется чем-то сложным. на само деле все довольно легко

maxpain commented 8 months ago

Может там в -t raw написано NOTRACK ?

iptables -t raw -S
-P PREROUTING ACCEPT
-P OUTPUT ACCEPT

virtual router только кажется чем-то сложным. на само деле все довольно легко

Да, попробую посмотреть в эту сторону тоже)

bol-van commented 8 months ago

Вот так у меня работает Вклинивание промежуточного виртуального узла между маршрутизацией подсети 192.168.1.0/24 в сеть 192.168.4.0/24 со шлюзом 192.168.4.1

ip netns add virt
ip link add veth0 type veth peer name veth1
ip link set netns virt veth1
ip addr add 172.31.255.253/30 dev veth0
ip -n virt addr add 172.31.255.254/30 dev veth1
ip link set dev veth0 up
ip -n virt link set dev veth1 up
ip r del default
ip r add default via 172.31.255.254 dev veth0

ip link add mvl1 link eth0 type macvlan mode bridge
ip link set mvl1 netns virt
ip -n virt link set dev mvl1 up
ip -n virt addr add 192.168.4.254/24 dev mvl1
ip -n virt r add default via 192.168.4.1 dev mvl1
ip -n virt r add 192.168.1.0/24 via 172.31.255.253  dev veth1

ip netns exec virt nft -n create table ip virt
ip netns exec virt nft -n create chain ip virt postrouting "{ type nat hook postrouting priority srcnat; policy accept; }"
ip netns exec virt nft -n add rule ip virt postrouting oifname mvl1 iifname veth1 masquerade
bol-van commented 8 months ago
ip netns exec virt nft create chain ip virt prerouting "{ type nat hook prerouting priority dstnat; policy accept; }"
ip netns exec virt nft add rule ip virt prerouting iifname veth1 tcp dport "{80,443}" redirect to :988
ip netns exec virt nft list ruleset
table ip virt {
        chain postrouting {
                type nat hook postrouting priority srcnat; policy accept;
                oifname "mvl1" iifname "veth1" masquerade
        }

        chain prerouting {
                type nat hook prerouting priority dstnat; policy accept;
                iifname "veth1" tcp dport { 80, 443 } redirect to :988
        }
}
ip netns exec virt /opt/zapret/tpws/tpws --debug --port 988 
Prepare bind 0 : addr= iface= v6=0 link_local=unwanted wait_ifup=0 wait_ip=0 wait_ip_ll=0
Binding 0 to [::]:988
Running as UID=2147483647 GID=2147483647
transparent proxy mode
TCP proxy mode (no tampering)
Original destination for socket fd=5 : 195.201.201.35:80
Legs : local:1 remote:1
Socket fd=5 (local) connected
Socket fd=6 (remote) connected
Socket fd=5 (partner_fd=6, remote=0) closed, connection removed. total_read=70 total_write=167 event_count=2
Socket fd=6 (partner_fd=0, remote=1) closed, connection removed. total_read=167 total_write=70 event_count=2
Legs : local:0 remote:0
bol-van commented 8 months ago

Что характерно, так это обработка на tpws в том числе и локальных соединений, рожденных из корневого неймспейса самого роутера. tpws их хватает в своем неймспейсе как prerouting входящие с интерфейса Получается, что я обрабатываю как входящие 192.168.1.1, так и рожденные на роутере, но все они становятся проходящими для неймспейса virt

В случае nat64 надо разобраться чем будут являться создаваемые им пакеты между адресами ipv4. Если он их сам генерит, то это получается OUTPUT. Или же он еще как-то хитро что-то делает, я в нем не разбирался. Но в любом случае эти пакеты должны свалиться в veth0 согласно таблице маршрутизации и попасть в veth1, а там свой network stack, который запустит нормальный процесс редиректа с prerouting

maxpain commented 8 months ago

https://nicmx.github.io/Jool/en/node-based-translation.html

Кажется проще будет запихать Jool в отдельный netns, завернуть на него 64:ff9b::/96 префикс (wg клиенты по этому префиксу обращаются когда хотят зайти на заблокированные сайты. Такие адреса генерирует мой DNS64 только для заблокированных сайтов), а zapret оставить в глобальном. Таким образом NAT64 преобразование будет в отдельном netns, из которого уже будет приходить IPv4 трафик в глобальный netns, где zapret уже будет обрабатывать его.

maxpain commented 8 months ago

Сделал вот так в общем, работает!

ip netns add jool
ip link add name to_jool type veth peer name to_world
ip link set up dev to_jool
ip link set dev to_world netns jool
ip netns exec jool ip link set up dev to_world
ip netns exec jool ip -6 route add default via fe80::bc10:ecff:fe0f:277 dev to_world
ip netns exec jool ip -4 address add 192.0.2.2/24 dev to_world
ip netns exec jool ip -4 route add default via 192.0.2.1 dev to_world

ip -6 route add 64:ff9b::/96 via fe80::24fc:24ff:fe9c:3f9a dev to_jool
ip -4 address add 192.0.2.1/24 dev to_jool

ip netns exec jool jool instance add --netfilter --pool6 64:ff9b::/96 nat64
ip netns exec jool jool --instance nat64 global update lowest-ipv6-mtu 1412
maxpain commented 8 months ago

@bol-van осталось понять что не так с MTU. Если делать запросы непосредственно с самой VM без Jool то полёт нормальный:

wget https://abs.twimg.com/responsive-web/client-web/main.a2166cda.js
--2024-02-24 14:21:54--  https://abs.twimg.com/responsive-web/client-web/main.a2166cda.js
Resolving abs.twimg.com (abs.twimg.com)... 152.199.21.141, 2606:2800:233:8173:898f:63b3:95c3:79d2
Connecting to abs.twimg.com (abs.twimg.com)|152.199.21.141|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2748467 (2.6M) [application/javascript]
Saving to: ‘main.a2166cda.js’

main.a2166cda.js                           100%[======================================================================================>]   2.62M  --.-KB/s    in 0.1s

2024-02-24 14:21:55 (19.9 MB/s) - ‘main.a2166cda.js’ saved [2748467/2748467]

А если через Jool, то скорость мизерная:

wget --no-check-certificate --header='Host: abs.twimg.com' https://[64:ff9b::98c7:18b9]/responsive-web/client-web/main.a2166cda.js
--2024-02-24 14:24:53--  https://[64:ff9b::98c7:18b9]/responsive-web/client-web/main.a2166cda.js
Connecting to [64:ff9b::98c7:18b9]:443... connected.
    WARNING: certificate common name ‘*.twimg.com’ doesn't match requested host name ‘64:ff9b::98c7:18b9’.
HTTP request sent, awaiting response... 200 OK
Length: 2748467 (2.6M) [application/javascript]
Saving to: ‘main.a2166cda.js.1’

main.a2166cda.js.1                           1%[>                                                                                      ]  32.00K  3.70KB/s    eta 10m 38s

Хм, проверил на другом домене, который nfqws тоже обрабатывает, такой проблемы нет.

wget --no-check-certificate --header='Host: st1-27.vk.com' "https://[64:ff9b::95.142.204.173]/dist/web/chunks/common.f36fd1b1.js"
--2024-02-24 17:40:00--  https://[64:ff9b::95.142.204.173]/dist/web/chunks/common.f36fd1b1.js
Connecting to 64:ff9b::95.142.204.173 (64:ff9b::95.142.204.173)|64:ff9b::5f8e:ccad|:443... connected.
    WARNING: certificate common name ‘*.userapi.com’ doesn't match requested host name ‘64:ff9b::95.142.204.173’.
HTTP request sent, awaiting response... 200 OK
Length: 2201018 (2.1M) [application/x-javascript]
Saving to: ‘common.f36fd1b1.js.4’

common.f36fd1b1.js.4                       100%[======================================================================================>]   2.10M  --.-KB/s    in 0.04s

2024-02-24 17:40:00 (56.0 MB/s) - ‘common.f36fd1b1.js.4’ saved [2201018/2201018]

Почему-то с доменом твиттера только такое, подумал может провайдер замедляет, но если без Jool скачивать то скорость не режется

bol-van commented 8 months ago

Как раз хотел сказать, что идея гонять zapret до jool так себе. Скорее всего он ломает значительную часть техник nfqws. Из tpws может сломать disorder

maxpain commented 8 months ago

Пофиксил вот так:

ip link set dev to_jool mtu 1412
ip netns exec jool ip link set dev to_world mtu 1412
maxpain commented 8 months ago

Спасибо за идею с netns!