Задача простая, но хочу поделиться; может быть будет полезно новичкам, тем более что в Zyxel пришлось править настройки файрвола. Понадобится знание маршрутизации, iptables и Linux:)
У меня есть VPSка (с CentOS) на одном хостере в Восточной Европе, решил направить трафик на некоторые сети через нее с моего Keenetic Ultra.
Выбирал между VPN на IPSec, OpenVPN и SSH Tunnel. Самый быстрый вариант наверное IPSec (потому что не заворачивается в userspace), но он самый сложный в настройке. В итоге остановился на OpenVPN и tun: tun это такой API в Linux когда траффик на виртуальный интерфейс сетевого уровня направляется в пользовательскую программу (OpenVPN в моем случае). Еще бывает tup, который эмулирует канальный уровень.
Сервер
На сервере поставил openvpn (``yum install openvpn``), настроил по https://openvpn.net/index.php/open-source/documentation/miscellaneous/78-static-key-mini-howto.html:
$ cat /etc/openvpn/server.conf
# хотим tun
dev tun
# IP сервера 172.16.1.1, IP клиента -- .2 (172.16. у нас приватная сетка)
ifconfig 172.16.1.1 172.16.1.2
# Будет слушать порт 443
port 443
# Будем работать по TCP
proto tcp-server
# Пингуем клиента каждые 10 секунд: если минуту не отвечает то считаем что отвалился
keepalive 10 60
# авторизироваться будем по ключу
secret static.key
Создал ключ в /etc/openvpn
$ openvpn --genkey --secret static.key
Запустил сервер (``systemctl enable openvpn@server && systemctl start openvpn@server``). У systemd юнита openvpn после собачки идет имя файла с конфигом.
Настройки iptables на centos хранятся в /etc/sysconfig/iptables, загружаются cat /etc/sysconfig/iptables | iptables-restore
Добавил в него NAT (тут написано что после роутинга, прямо перед отправкой пакета в Интернет (интерфейс venet) если он пришел из сети с VPN (см адрес) нужно поменять source на внешний IP ):
Получился обычный SNAT
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [1:76]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 172.16.1.0/24 -o venet+ -j SNAT --to [ВНЕШНИЙ_IP]
COMMIT
*filter
:INPUT DROP [83:5616]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [6911:1304844]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
...тут всякие мои правила
-A INPUT -s [ДОМАШНИЙ_МОЙ_ВНЕШНИЙ_IP] -m state --state NEW -p tcp --dport 443 -j ACCEPT
-A INPUT -i tun+ -j ACCEPT
-A FORWARD -i tun+ -o venet+ -j ACCEPT
-A FORWARD -i venet0 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
...и в filter: тут написано что с моего домашнего IP можно цепляться на порт 443, и что между внешним интерфейсом и tun (нашим VPN) можно пускать траффик: с VPN любой, а обратно только если он идет в ответ.
Zyxel
Скопировал себе static.key.
Поставил через opkg openvpn-ssl.
Настраиваем клиента /opt/etc/openvpn/openvpn.conf
remote [МОЙ_СЕРВЕР] 443 tcp-client
dev tun
ifconfig 172.16.1.2 172.16.1.1
connect-retry 15
connect-retry-max infinite
keepalive 10 60
resolv-retry infinite
route-up /opt/etc/openvpn/route.sh
secret /opt/etc/openvpn/static.key
Тут всё как на сервере, только мы tcp-client, пытаемся достучаться каждые 15 секунд (это важно, ведь у меня связь с провайдером по L2TP/IPSec, а оно иногда рвется!).
Так же указан ключик с секретом (скопированный!) и скрипт, который будет запускаться как только поднялся OpenVPN и будет править маршрутизацию.
На Zyxel systemd нету, так что у нас обычный systemV init: скрипт ``/opt/etc/init.d/S20openvpn`` поставится с Openvpn и будет запускаться при загрузке (ну или его можно start)
Запустил скрипт, в журнале увидел что соединение установлено, пошли пинги на интерфейс: ping 172.16.1.1
Тут началось интересное: маршрутизацией Zyxelевая прошивка управляет сама: она NATит весь траффик из локалки (интерфейс br0 -- видимо потому что bridge с другими ethernet портами на роутере) но по-умолчанию разрешает его только на ppp (то-есть на VPN с провайдером). Если добавить iptables -I INPUT -s [моя локалка] -j ACCEPT явно, то zyxel его перепишет.
Внести постоянные изменения можно через утилиту ndmc, или через UI.
Я пошел в UI и в сетевом экране для интерфейса Home добавил разрешение для TCP, UDP и ICMP куда угодно для 192.168.1.0/255.255.255.0 (такая у меня локалка)
Теперь с домашних компов пошли пинги на сервер интерфейса 172.16.1.1.
Осталось добавить маршруты в наш
# /opt/etc/openvpn/route.sh
#!/bin/sh
# Network1
route add -net [СЕТКА_НА_КОТОРУЮ_Я_ХОЧУ_ХОДИТЬ_ЧЕРЕЗ_VPS] gw 172.16.1.1
route add -net [ЕЩЕ_СЕТКА_НА_КОТОРУЮ_Я_ХОЧУ_ХОДИТЬ_ЧЕРЕЗ_VPS] gw 172.16.1.1
Запустил скрипт и вуаля: иду на с домашнго компа на машину в той сети, и вижу что пришел туда не от своего провайдера, а со своего сервера:)
На всякий случай еще раз, вот как идет пакет:
1) С домашнего компа идет на роутер
2) Роутер по маршрутизации понимает что его надо направить на VPS
3) Делает NAT (заменяет source адрес на 172.16.2.1)
4) Шлет его на сервер
5) Сервер опять меняет ему SRC на свой внешний IP
6) Шлет его в Интернет
7) В Интернет приходит мой пакет от имени моего сервера
Хорошо что не смотря на проприетарную прошивку, Zyxel это самый настоящий Linux роутер)
Теперь хочу сделать скрипт, который будет собирать список нужных мне сетей и выгружать их по cronу в route.sh. Если не хватит моих знаний sed/awk/shell, то придется ставить из opkg какой-то скриптовый язык. Вроде, там есть python:)