Предстала когда-то задача - выпустить из локальной сети трафик одного девайса (смартфона) так, чтобы в логах сайтов, куда будет сей девайс ходить, светился IP-адрес некоторого заморского сервера, расположенного в Австралии. Смартфон этот никаких средств организации VPN-ов не имел и даже был неспособен работать через прокси, в интернет ходил через Wi-Fi. Локальная сеть с Wi-Fi и смартфоном расположена в Киеве, в Интернет ходит через NAT.
- На австралийском сервере c именем remote.server.au строим VPN-сервер, например pptpd
- На офисном роутере R настраиваем VPN-клиент, например pptp, подключаемся к VPN-серверу, например, так:
pppd pty 'pptp remote.server.au --nolaunchpppd' call sidney debug dump logfd 2 nodetach
имя сеанса sidney (после call) должно соответствовать прописанному в файле /etc/ppp/chap-secrets, nodetach --- необязательно, я его использовал для отслеживания процесса.
- Маршрутизация работает на основе IP-адреса назначения (destination IP-address), то есть для решения через какой интерфейс отправлять пакет принимается только этот адрес. А в нашей ситуации требуется обратное --- маршрутизировать через Сидней трафик одного только смартфона на основе его IP-адреса, а всех остальных клиентов локальной сети не трогать. Этого можно достичь благодаря одному замечательному умению linux, которое называется policy routing. Создаём еще одну таблицу с произвольным именем (я выбрал avztable) для правил маршрутизации на основе IP-адреса отправителя. Эта новая таблица будет жить параллельно и независимо от основной таблицы маршрутизации с названием main. Для этого в /etc/iproute2/rt_tables, добавляем строчку
252 avztable
- Создаём правило для маршрутизации по source-адресу:
ip rule add from 192.168.1.55 lookup avztable
- Разворачиваем трафик смартфона в туннель путём добавления маршрута по-умолчанию в таблицу avztable:
ip r a default via 192.168.0.1 table avztable
Здесь 192.168.0.1 --- адрес VPN-сервера, который становится доступным после поднятия туннеля, задаётся в /etc/pptpd.conf в Сиднее.
- В Сиднее добавляем правило для правильной маршрутизации входящего к смартфону трафика. Я для этого наваял такой простенький скрипт и засунул его в cron:
net='192.168.1.0/24' /sbin/ip r s | grep "$net" > /dev/null || { gw=`/sbin/ip a s | grep -E "ppp[0-9]" | grep inet | sed -r "s/.*peer[[:space:]]([^/]+)\/.*/\1/"` if [ ! -z $gw ]; then echo "setting route to net $net via $gw" /sbin/ip r a $net via $gw fi }
Во 2-ой строке проверяем наличие маршрута в таблице маршрутизации, если правила нет, идём дальше. В 3-ей строчке вычисляем IP-адрес VPN-клиента (офисного роутера), который подключился из Киева. В 6-ой строчке собственно добавляем маршрут. После чего австралийский сервер будет знать, что трафик с адресами назначения из сети 192.168.1.0/24 (куда входит наш смартфон), нужно слать в туннель, а не своему default gateway. Правильнее было бы, конечно, вызывать этот скрипт не из cron, а один раз сразу после установки туннеля. Но мне было лениво искать как это сделать автоматически.
- В Сиднее проверяем firewall, должно быть что-то такое:
IPT=/sbin/iptables $IPT -A INPUT -p 47 -j ACCEPT $IPT -A INPUT -p tcp --dport 1723 -j ACCEPT $IPT -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT $IPT -A FORWARD -s 192.168.1.55 -m comment --comment "phone" -j ACCEPT $IPT -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
2-ая и 3-яя строчки нужны для того, чтобы можно было подключиться к VPN-серверу. В 4-ой и 5-ой разрешаем транзитный трафик от и к смартфону. В 6-ой включаем NAT, так чтобы серый адрес смартфона транслировался в в честный адрес австралийского сервера (eth0 - интерфейс в сторону Интернет).
- Включаем форфардинг между интерфейсами на сервере в Сиднее:
sysctl -w net.ipv4.ip_forward = 1
Идём броузером со смартфона для проверки на какой-нибудь looking-glass и проверяём, что он нам показывает IP-адрес австралийского сервера.
Изящное решение. Взял на заметку. Нашим тестерам часто такое бывает надо...
Реально прикольно. Мне тоже такое надо было сделать недавно, да я не придумал как. Теперь знаю, спасибо!