FreeBSD. Перенаправление исходящего трафика по VPN через ipfw forward
Понадобилось перенаправлять исходящий с сервера трафик через VPN, но при этом сервер должен продолжать обслуживать все запросы по существующему внешнему интерфейсу (например веб-сервер, ssh, dns и прочие сервисы должны продолжать работать как ни в чем не бывало). Это может быть полезным при краулинге, если у какого-то сайта (источника данных) установлены квоты на частоту реквестов и т.п., то мы просто используем VPN с Dynamic IP, а наш сайт на этом же сервере продолжает обслуживать клиентов.
Имеем FreeBSD и ipfw, а также openvpn-клиент и mpd5. Вообще, VPN подойдет любой (но примеры будут для OpenVPN и PPTP), нам главное чтобы поднимался интерфейс в системе, на который мы разрешим отправлять данные.
Итого, мы имеем два интерфейса:
- bce0 - gateway 203.0.113.1, ip 203.0.113.11, Static IP
- tun0 - gateway 10.8.1.1, ip 10.8.1.17, Dynamic IP
Прикладываю схему иллюстрирующую это:

С виду всё просто, у ipfw есть forward, сейчас мы подключимся по VPN и поднимем сетевой интерфейс, и нужные данные будем туда слать, всё. Но проблема в том, что у нас VPN с Dynamic IP, и мы не можем зафиксировать полученный динамически IP-адрес в конфиге ipfw, а указать сетевой интерфейс tun0 для forward просто невозможно. Можно конечно выдумать велосипед, который будет менять в ipfw правила после переподключения интерфейса, но должно быть решение проще.
Спрося на форуме лисяры и после переосмыслив задачу я понял, что можно поступить наоборот, при подключении по VPN надо разрешить pull в роуты (т.е. будет заменен default-gateway на полученный от VPN-провайдера, интерфейс tun0), и сделать правила для внешнего интерфейса bce0. Вот такое правило в итоге получилось:
# ipfw add fwd <IPv4-address-from-bce0-gateway> all from <IPv4-address-from-bce0> to any ipfw add fwd 203.0.113.1 all from 203.0.113.11 to any
Здесь мы перенаправляем все ip-пакеты полученные с 203.0.113.11 на шлюз 203.0.113.1.
Теперь посмотрим текущие маршруты до подключения по VPN:
$ netstat -rn Routing tables Internet: Destination Gateway Flags Refs Use Netif default 203.0.113.1 UGS 0 288182787 bce0 203.0.113.0/26 link#2 U 0 48030001 bce0 203.0.113.11 link#2 UHS 0 1191123263 lo0 127.0.0.1 link#5 UH 0 2765661929 lo0
Подключаемся по VPN...
Я выбрал в качестве провайдера OpenVPN , но скорость работы после подключения была катастрофическая, без VPN реквесты выполнялись в среднем за 0.3-0.5 sec, после подключения за 5-20 sec. Пример конфига /usr/local/etc/openvpn/vpntunnel.conf:client dev tun proto udp ca /usr/local/etc/openvpn/vpntunnel_keys/ca1.crt ns-cert-type server cipher BF-CBC resolv-retry infinite auth-user-pass /usr/local/etc/openvpn/vpntunnel_auth.conf ;route-noexec ;route-nopull remote-random remote ru-vpn.vpntunnel.se 7001 remote ru-vpn.vpntunnel.se 7002 remote ru-vpn.vpntunnel.se 7003 remote ru-vpn.vpntunnel.se 7004 remote ru-vpn.vpntunnel.se 7005 remote ru-vpn.vpntunnel.se 7006 remote ru-vpn.vpntunnel.se 7007 remote ru-vpn.vpntunnel.se 7008 remote ru-vpn.vpntunnel.se 7009 persist-key persist-tun nobind comp-lzo log-append /var/log/vpn/vpntunnel.log verb 4 mute 20
Добавим openvpn в /etc/rc.conf:openvpn_enable="YES" openvpn_if="tun" openvpn_configfile="/usr/local/etc/openvpn/vpntunnel.conf"
Запускаем openvpn:/usr/local/etc/rc.d/openvpn start
В качестве провайдера PPTP был выбрал , тут скорость реквестов была не больше 0.5 sec, что конечно обрадовало, но оказалось что заявленный Dynamic IP и поддержка OpenVPN есть только в Windows-клиенте. Пример конфига /usr/local/etc/mpd5/mpd.conf:default: load pptp_client pptp_client: create bundle static B1 set iface route default # set iface up-script /usr/local/etc/mpd5/hotvpn_up.sh # set iface down-script /usr/local/etc/mpd5/hotvpn_down.sh set ipcp ranges 0.0.0.0/0 0.0.0.0/0 set bundle enable compression set ccp yes mppc set mppc yes e40 set mppc yes e128 set mppc yes stateless create link static L1 pptp set link action bundle B1 set auth authname <username> set auth password <password> set link max-redial 0 set link mtu 1460 set link keep-alive 20 75 set pptp peer ru.hotvpn.com set pptp disable windowing open
Добавим mpd5 в /etc/rc.conf:mpd5_enable="YES"
Запускаем mpd5:/usr/local/etc/rc.d/mpd5 start
В случае с PPTP будет поднят интерфейс ng0, а не tun0, но все остальное остается в силе.
Подключаемся по VPN и смотрим новые маршруты:
$ netstat -rn Routing tables Internet: Destination Gateway Flags Refs Use Netif default 10.8.1.1 UGS 0 33562412 tun0 10.8.1.1 link#7 UH 0 0 tun0 10.8.1.17 link#7 UHS 0 0 lo0 203.0.113.0/26 link#2 U 0 179047 bce0 203.0.113.11 link#2 UHS 0 239069 lo0 127.0.0.1 link#5 UH 0 214629971 lo0
Ну всё, теперь должна работать заявленая в начале статьи схема. Смотрите вывод ipfw show.
Сборка ядра с поддержкой ipfw fwd
Для реализации нам понадобится поддержка fwd (forward) в ipfw. Если у вас ядро собрано без поддержки IPFIREWALL_FORWARD, то придется пересобирать его, для этого мы скопируем ядро GENERIC и добавим нужные опции. Перейдите в каталог с исходниками FreeBSD:
cd /usr/src ls
Если ничего нет, то надо скачать исходники, для FreeBSD 9 они находятся тут:
svn co /usr/src
В зависимости от архитектуры процессора, надо выбрать каталог, в моем случае это amd64:
cd /usr/src/sys/amd64/conf/
Теперь скопируем конфиг для ядра, для примера я его назвал MY_KERNEL:
cp GENERIC MY_KERNEL
Теперь добавим IPFIREWALL_FORWARD и некоторые другие опции в MY_KERNEL:
options IPFIREWALL options IPFIREWALL_VERBOSE options IPFIREWALL_VERBOSE_LIMIT=100 options IPFIREWALL_FORWARD options IPDIVERT
Для удобства, отредактируем /etc/make.conf:
NO_PROFILE=YES CFLAGS= -O2 -pipe KERNCONF=MY_KERNEL
Добавляем пользователя "auditdistd", он понадобится при установке, смотрите "/usr/src/UPDATING":
pw useradd auditdistd -G wheel
Перед запуском, на всякий случай, сделайте бекап "/etc":
tar -czf /home/username/etc.tgz /etc
Собираем мир, ядро:
cd /usr/src make buildworld make buildkernel make installkernel
Если будете использовать mergemaster -p, то сделайте бекап "/etc", так как придется мержить конфиги и легко ошибится, а если вы затронули файл с паролями пользователей, то перед ребутом ОС выполните password root, иначе не сможете войти.
reboot
Инструкции по сборке ядра можете смотреть тут.
Комментарии
Уважаемый Михаил! Извиняюсь что не по теме но в вашем вишлисте увидел книжку Никлауса Вирта по алгоритмам и структурам данных. Хотел спросить читали ли вы ее? Если да то какие впечатления? Книжку посмотрел на озоне, она достаточно маленькая если учитывать вес и объем других книг по данной тематики. Да и еще примеры на обероне :-) Но советуют ее многие.
Добрый день, вот пост об этом http://adw0rd.com/2012/10/3/bought-4-books-today/
Я её давно читал в интернете, поэтому и купил, это классика. Бумажную версию ещё не перечитывал :-)
По ссылке только обложки книг :-) Я хотел узнать ваше мнение об этой книге :-)
Ну как я и сказал это классика, там все хорошо описано
Михаил подскажите пожалуйста как данную задачу реализовать на ubuntu, я так понимаю, там нужно прописать iptables правила и настроить ip forwarding.
Но вот знаний в этой области не хватает уже весь интернет перерыл в поиске решения данной задачи, кроме Вас я так понял ни кто подобного не делал. Возможно вы сможете помочь мне с этой проблемой, очень на Вас надеюсь, спасибо.
@Денис, посмотрите мои другие статьи http://adw0rd.com/tag/vpn/
В других статьях в основном про Ubuntu, с примерами на iptables
Вот тут все ответы есть http://adw0rd.com/2013/1/10/openvpn/
Прочитал ваши статьи, но там конкретно не нашел то что мне нужно, либо я не до конца понял как это правильно настраивается, пользуясь возможностью задам вопрос специалисту. Итак, есть VPN сервер PPTP, есть клиент ubuntu сервер. Необходимо подключиться к VPN серверу таким образом чтоб можно было обслуживать все запросы по существующему внешнему интерфейсу, в данном случае это eth0. В моем случае мне не удается таким образом подключиться по ip хостера, при активном VPN соединении как только отключаюсь от сети VPN, могу спокойно подключится по ip хостера. То есть мне необходимо чтоб сайт был доступен по своему IP который дает хостер при активном соединении с VPN сервером и весь исходящий трафик с сайта шел через VPN. Мне нужно на стороне клиента прописать правила iptables и все?? Или еще на VPN сервере необходимо что то прописывать чтоб добиться реализации данной задачи, заранее спасибо за Ваш ответ. Ни когда ранее подобного не настраивал, так что не судите строго.
Оставьте свой комментарий