Таким образом, в вашей конфигурации все пакеты, которые вы пытаетесь отправить в сеть, изначально исходят 10.0.0.1
(потому что они проходят через tun0
интерфейс и его локальный адрес есть 10.0.0.1
). Вы захватываете пакеты, пока все в порядке.
Теперь tun0
отправляет пакеты дальше. Адрес источника есть, 10.0.0.1
и вы хотите, чтобы пакеты выходили через другой интерфейс ( wlp2s0
в вашем случае). Это маршрутизация, поэтому давайте сначала включим маршрутизацию:
sysctl -w net.ipv4.ip_forward=1
После этого, если вы будете смотреть на tcpdump
для wlp2s0
вы можете заметить , что пакеты оставить с адресом источника , 10.0.0.1
а не с исходным адресом интерфейса беспроводной ЛВС (что можно было бы ожидать , я думаю). Поэтому нам нужно изменить адрес источника, и он называется NAT источника . В Linux это легко с помощью netfilter / iptables :
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.1 -j MASQUERADE
Также проверьте, что в вашей FORWARD
цепочке есть ACCEPT
политика или вам нужно разрешить пересылку с чем-то вроде:
iptables -A FORWARD -i tun0 -o wlp2s0 -s 10.0.0.1 -j ACCEPT
iptables -A FORWARD -i wlp2s0 -o tun0 -d 10.0.0.1 -j ACCEPT
Теперь все должно работать: ядро Linux выполняет маршрутизацию, оно перемещает пакеты из tun0
интерфейса в wlp2s0
. netfilter должен изменить IP- адрес источника 10.0.0.1
на wlp2s0
адрес, назначенный вашему интерфейсу для выходных пакетов. Он запоминает все соединения и, когда ответные пакеты возвращаются (если они есть), меняет адрес назначения назначенного wlp2s0
интерфейса интерфейса 10.0.0.1
(функция «conntrack»).
Ну, это должно быть, но это не так. Кажется, netfilter путается с этой сложной конфигурацией маршрутизации и тем фактом, что один и тот же пакет сначала проходит через OUTPUT
цепочку, а затем маршрутизируется и попадает в PREROUTING
цепочку. По крайней мере, на Debian 8 box это не работает.
Лучший способ устранения неполадок с сетевым фильтром - это TRACE
функция:
modprobe ipt_LOG
iptables -t raw -A OUTPUT -p icmp -j TRACE
iptables -t raw -A PREROUTING -p icmp -j TRACE
Я включаю трассировку только для пакетов ICMP, вы можете использовать другой фильтр для отладки.
Он покажет, через какие таблицы и цепочки проходит пакет. И я вижу , что пакет не идет далее FORWARD
цепь (и это не пойманы nat/POSTROUTING
цепи , которая на самом деле делает SNAT
).
Ниже приведены несколько подходов, чтобы сделать эту работу.
ПОДХОД № 1
Лучший способ не путать netfilter - это изменить исходный IP-адрес пакетов в tun0.c
приложении. Это также самый естественный способ. Нам нужно изменить 10.0.0.1 на 10.0.0.2 на обратном пути и 10.0.0.2 на 10.0.0.1 на обратном пути.
Я изменил tun0.c
с кодом изменения исходного адреса. Вот новый файл и вот патч- файл для вашего tun0.c
. Изменения в заголовке IP также включают исправление контрольной суммы , поэтому я взял некоторый код из проекта OpenVPN . Вот полный список команд, которые я выполняю после чистой перезагрузки и tun0_changeip.c
запуска:
ifconfig tun0 inet 10.0.0.1/30 up
sysctl -w net.ipv4.ip_forward=1
ip route add default dev tun0 table John
ip rule add from all lookup John
ip rule add from 10.0.0.2 lookup main priority 500
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.0.2 -j MASQUERADE
Обратите внимание, что вам не нужно отключать фильтрацию обратного пути в этом случае, потому что все законно - tun0
только получает и отправляет пакеты, которые принадлежат его подсети. Также вы можете сделать маршрутизацию на основе источника вместо интерфейса.
ПОДХОД № 2
Это можно сделать SNAT
до того, как пакет достигнет tun0
интерфейса. Это не очень правильно, хотя. Вам обязательно нужно отключить фильтрацию обратного пути в этом случае:
sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0
Теперь выполните SNAT
: iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT - к источнику ip.address.of.your.wlan.interface
Здесь мы меняем адрес источника непосредственно перед тем, как пакеты достигают tun0
устройства. tun0.c
Код отправляет эти пакеты «как есть» (с измененным адресом источника), и они успешно маршрутизируются через интерфейс WLAN. Но у вас может быть динамический IP на интерфейсе WLAN и вы хотите использовать MASQUERADE
(чтобы не указывать адрес интерфейса явно). Вот как вы можете использовать MASQUERADE
:
iptables -t nat -A POSTROUTING -o tun0 -s 10.0.0.1 -j SNAT --to-source 10.0.55.1
iptables -t nat -A POSTROUTING -o wlp2s0 -s 10.0.55.1 -j MASQUERADE
Обратите внимание на « 10.0.55.1
» IP-адрес - это другое. Вы можете использовать любой IP здесь, это не имеет значения. Пакеты достигают nat/POSTROUTING
цепочки на wlp2s0
интерфейсе, если мы изменим исходный IP раньше. И теперь это не зависит от статического IP-адреса для интерфейса WLAN.
ПОДХОД № 3
Вы также можете использовать fwmark
. Таким образом , вам не нужно , SNAT
но вы будете захватывать только исходящие пакеты:
Сначала нужно отключить обратный путь фильтрации для tun0
потому что он будет пересылать пакеты , которые принадлежат к другой сети:
sysctl -w net.ipv4.conf.tun0.rp_filter=0
# It won't work without also changing the "all" value
sysctl -w net.ipv4.conf.all.rp_filter=0
Now let's alter the routing rules a bit:
# Delete old rules
ip rule del iif tun0 lookup main
ip rule del from all lookup John
# Packets will start going from wlan interface so they will have source address of it
iptables -t mangle -A OUTPUT -o wlp2s0 -j MARK --set-mark 1
ip rule add fwmark 0x1 lookup John
Это еще один «хак» для маршрутизации и сетевого фильтра, который работает на моем компьютере с Debian 8, но все же я рекомендую использовать первый подход, так как он более естественный и не использует никаких хаков.
Вы также можете рассмотреть возможность создания приложения в качестве прозрачного прокси . Я думаю, что было бы гораздо проще, чем анализировать пакеты с устройства Tun.
-j SNAT
, а не-s SNAT