14 марта 2013 г. FreeBSD IPFW VPN OpenVPN

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 http://vpntunnel.com/ , но скорость работы после подключения была катастрофическая, без 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 был выбрал http://www.hotvpn.com/ , тут скорость реквестов была не больше 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 http://svn.freebsd.org/base/stable/9 /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 сервере необходимо что то прописывать чтоб добиться реализации данной задачи, заранее спасибо за Ваш ответ. Ни когда ранее подобного не настраивал, так что не судите строго.

Оставьте свой комментарий

Markdown