Удаленный доступ к локальной сети через сервер FreeBSD в режиме моста

Исходная задача выглядит следующим образом. Есть сервер под управлением ОС FreeBSD, обеспечивающий доступ к Internet для локальной сети. Необходимо организовать прозрачный доступ к ней посредством VPN из любой точки Internet. Т.е. реализовать функционал подобный RRAS под ОС Windows Server с использованием PPTP.
Для решения данной задачи я выбрал OpenVPN. В первую очередь потому, что этот продукт бесплатен, существуют его реализации под все распространенные платформы, не имеет никаких проблем с NAT. Ко всему прочему встречаются случаи, когда операторы беспроводного доступа к Internet блокируют в своих сетях трафик IPSec или GRE. Но OpenVPN не лишен недостатков. Первым бы я отметил тот факт, что данный продукт, как обычный демон, полностью работает в userspace, что негативным образом сказывается на производительности по сравнению с реализацией IPSec, которая функционирует преимущественно на уровне ядра. Вторым недостатком мною отмечена не очень стабильная работа программы. Например, реализация драйвера TAP для Windows находится в состоянии бета. А в процессе тестирования я регулярно сталкивался с тем, что под ОС Windows 7 x64 при первом запуске после загрузки компьютера OpenVPN GUI закрывался с ошибкой при подключении к серверу. Приходилось с помощью диспетчера задач принудительно снимать процесс «openvpn.exe», и запускать OpenVPN GUI повторно. После этого никаких проблем больше не возникало. В то же самое время на ОС Windows XP x86 таких проблем не было.
В нашей конфигурации сервер работает под управлением ОС FreeBSD v9.1, его WAN интерфейсу присвоен реальный адрес 78.121.108.252. В локальной сети используется адресация 192.168.58.0/24, сетевой интерфейс LAN сервера носит название rl0 и задействует адрес 192.168.58.1. Рабочим станциям адреса назначаются с помощью сервера DHCP, под это выделен пул 192.168.58.64 – 192.168.58.254. А для OpenVPN зарезервирован блок 192.168.58.56 – 192.168.58.63.
Удаленно подключающиеся пользователи должны иметь прозрачный доступ к локальной сети, для этого необходимо, что бы сервер работал в режиме моста сети Ethernet. Это требует поддержки функционала моста и интерфейсов tap в ОС FreeBSD. Вносим соответствующие опции в конфигурацию ядра:

device tap
device if_bridge

Либо можете организовать загрузку соответствующих модулей через «/boot/loader.conf».
Из системы портов устанавливаем security/openvpn:

OpenVPN 2.3.0 amd64-portbld-freebsd9.1

Из соображений безопасности работать OpenVPN будет под одноименным непривилегированным пользователем и группой. Создадим их:

pw groupadd openvpn -g 137
pw useradd openvpn -u 137 -g 137 -s /usr/sbin/nologin -n openvpn -L nologin -d /nonexistent -c "OpenVPN daemon"

Для удобства логи OpenVPN будем писать в отдельный файл. Модифицируем «/etc/syslog.conf»:

!openvpn
*.* /var/log/openvpn.log

И не забудем о ротации log-файла в «/etc/newsyslog.conf»:

/var/log/openvpn.log 600 10 300 * J

Для упрощения управления SSL-сертификатами устанавливаем из портов security/ssl-admin. Однако, аутентифицировать пользователей я собираюсь не с помощью сертификатов, а вполне традиционно: имя и пароль. Вместе с тем использовать системную базу пользователей ОС FreeBSD не хочу из соображений все той же безопасности. Создадим для этого отдельную базу под OpenVPN. Для этого ставим из портов PAM-модуль security/pam_pwdfile. Он аутентифицирует через тестовые файлы, содержащие пару: имя пользователя и хешированный пароль. Для управления такого типа файлами удобно использовать утилиту chpwdfile, ссылка на которую содержится в README security/pam_pwdfile. chpwdfile в портах отсутствует, компилируется и устанавливается прямо из исходников. Либо можете воспользоваться утилитой htpasswd из комплекта Web-сервера Apache. Если же вы все-таки остановили свой выбор на chpwdfile, то создайте для нее файл настроек «/etc/chpwdfile.conf»:

file=/usr/local/etc/openvpn/openvpn.passwd
minpassword=8
minusername=3
hashtype=m
end

Создайте каталог «/usr/local/etc/openvpn/» и добавьте в файл «/usr/local/etc/openvpn/openvpn.passwd» хотя бы одного пользователя. Переходим к настройке PAM. Она сводится к созданию файла «/usr/local/etc/pam.d/openvpn» следующего содержания:

auth requisite /usr/local/lib/pam_pwdfile.so pwdfile /usr/local/etc/openvpn/openvpn.passwd
account optional pam_permit.so
session optional pam_permit.so
password optional pam_permit.so

Создаем файл настроек сервера OpenVPN «/usr/local/etc/openvpn/openvpn.conf»:

local 78.121.108.252
dev tap
proto udp
server-bridge 192.168.58.1 255.255.255.0 192.168.58.56 192.168.58.63
push "route 192.168.0.0 255.255.0.0"
push "dhcp-option DNS 192.168.58.1"
push "dhcp-option NTP 192.168.58.1"
push "dhcp-option DOMAIN local.lan"
push "ip-win32 dynamic 0 3600"
push "comp-lzo yes"
push "inactive 3600"
push "ping 10"
push "ping-exit 60"
client-to-client
duplicate-cn
user openvpn
group openvpn
plugin /usr/local/lib/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn
client-cert-not-required
username-as-common-name
up "/usr/local/etc/openvpn/up-bridge.sh"
down "/usr/local/etc/openvpn/down-bridge.sh"
plugin /usr/local/lib/openvpn/plugins/openvpn-plugin-down-root.so "/usr/local/etc/openvpn/down-bridge.sh"
max-clients 8
comp-lzo yes
keepalive 10 120
status /usr/local/etc/openvpn/openvpn.status 180
status-version 3
persist-key
persist-tun
verb 3
mute 30
mssfix 1450
tun-mtu 1500
fragment 1300
dh /usr/local/etc/openvpn/dh2048.pem
ca /usr/local/etc/openvpn/ca.crt
cert /usr/local/etc/openvpn/cert.crt
key /usr/local/etc/openvpn/key.key
script-security 2
client-connect "/usr/local/etc/openvpn/client-connect.sh"
client-disconnect "/usr/local/etc/openvpn/client-disconnect.sh"

Для корректной работы security/ssl-admin необходимо создать файл с клиентскими настройками OpenVPN: «/usr/local/etc/ssl-admin/packages/client.ovpn». Он может быть пустым.
Несмотря на то, что аутентификация удаленных пользователей производится посредством имени и пароля, для работы OpenVPN все равно нужны SSL-сертификаты, как минимум для шифрования посредством TLS управляющего канала, дабы пароли не передавались через Internet в открытом виде. Займемся сертификатами. Заполняем настройки в файле «/usr/local/etc/ssl-admin/ssl-admin.conf» и запускаем ssl-admin:
ssl-admin Набираем CA и генерируем корневой сертификат, S – сертификат для сервера OpenVPN, 4 и z – сертификат для клиентов, он в моем случае будет один на всех, поскольку аутентификация фактически будет происходить по имени и паролю, и последнее dh – файл с параметрами для алгоритма Диффи-Хеллмана. Копируем ключи и сертификаты сервера в «/usr/local/etc/openvpn/».
При запуске OpenVPN будет создавать сетевой интерфейс туннелирования tap0, через который проходит трафик от удаленных пользователей. Он должен коммутироваться через мост с интерфейсом LAN. Для этого создается скрипт «/usr/local/etc/openvpn/up-bridge.sh», который будет запускаться OpenVPN при каждом своем старте:

#!/bin/sh

/sbin/ifconfig bridge0 addm ${dev}
/sbin/ifconfig ${dev} up

exit 0

При остановке OpenVPN будет запускаться скрипт «/usr/local/etc/openvpn/down-bridge.sh», который удаляет интерфейс tap0:

#!/bin/sh

/sbin/ifconfig bridge0 deletem ${dev}
/sbin/ifconfig ${dev} destroy

exit 0

В процессе тестирования мною был выявлен небольшой глюк в работе механизма моста под ОС FreeBSD. Выражается он в том, что если следом за только что отключившимся от OpenVPN пользователем сразу подключается новый и получает IP-адрес предыдущего, то ему недоступен сам сервер по IP-адресу 192.168.58.1. Для устранения этой проблемы был создан скрипт, чистящий таблицы ARP и FDB при каждом подключении/отключении пользователя. Содержимое «/usr/local/etc/openvpn/client-connect.sh»:

#!/bin/sh

sudo="/usr/local/bin/sudo"
arp="/usr/sbin/arp"
awk="/usr/bin/awk"

mac=`${sudo} ${arp} -n ${ifconfig_pool_remote_ip}`

if [ -n "${mac}" ]
then
mac=`/bin/echo ${mac} | ${awk} -F "at " $'{print$2}' | ${awk} -F " on" $'{print$1}' | /usr/bin/sed '/^ *$/d' | /usr/bin/sort | /usr/bin/uniq -u`

for i in ${mac}
do
${sudo} /sbin/ifconfig bridge0 deladdr ${i}
done
fi

${sudo} ${arp} -d ${ifconfig_pool_remote_ip}

exit 0

«/usr/local/etc/openvpn/client-disconnect.sh» является просто символической ссылкой:

ln -s /usr/local/etc/openvpn/client-connect.sh /usr/local/etc/openvpn/client-disconnect.sh

Однако данные скрипты не в состоянии очистить таблицу ARP виртуального интерфейса tap0. При выполнении команды arp -d выводится сообщение об ошибке «arp: writing to routing socket: Invalid argument», и соответствующий MAC-адрес продолжает числиться за tap0. Но, тем не менее, к каким-либо проблемам в работе это не приводит.
arp -d

Не забудьте сделать все созданные скрипты исполняемыми.
Внимательный читатель заметил, что в работе скриптов client-connect.sh/client-disconnect.sh используется security/sudo. Если эта утилита еще не стоит у вас в системе, поставьте из портов. Напоминаю, что OpenVPN у нас работает от лица непривилегированного пользователя, прав которого недостаточно для выполнения команд arp и ifconfig. Тут нам на помощь приходит sudo. Отредактируйте «/usr/local/etc/sudoers», добавив в него следующие строки:

Host_Alias GW = gw
Cmnd_Alias OPENVPN = /usr/sbin/arp, /sbin/ifconfig
openvpn GW = (root) NOPASSWD: OPENVPN

Переходим к заключительному этапу настройки серверной части OpenVPN. Добавляем в «/etc/rc.conf» настройки, которые создают бриджовый интерфейс:

cloned_interfaces=″bridge0″
ifconfig_bridge0=″addm rl0 up″

И размещаем запуск OpenVPN:

openvpn_enable=″YES″
openvpn_if=″tap bridge″
openvpn_configfile=″/usr/local/etc/openvpn/openvpn.conf″
openvpn_dir=″/usr/local/etc/openvpn″

Собственно запускаем сервер:

/usr/local/etc/rc.d/openvpn start

Дистрибутивы OpenVPN для ОС Windows можно скачать здесь: http://openvpn.net/index.php/download/community-downloads.html Устанавливаем в каталог по умолчанию: «C:\Program Files\OpenVPN\». Не забудьте про драйвер TAP-Win32. Создаем файл настроек «C:\Program Files\OpenVPN\config\client.ovpn»:

client
dev tap
proto udp
remote 78.121.108.252 1194 udp
nobind
persist-key
persist-tun
mute-replay-warnings
ca "C:\\Program Files\\OpenVPN\\config\\ca.crt"
cert "C:\\Program Files\\OpenVPN\\config\\openvpn.crt"
key "C:\\Program Files\\OpenVPN\\config\\openvpn.key"
dh "C:\\Program Files\\OpenVPN\\config\\dh2048.pem"
remote-cert-tls server
comp-lzo yes
verb 3
mute 30
inactive 3600
ping 10
ping-exit 60
mssfix 1450
tun-mtu 1500
fragment 1300
auth-user-pass "C:\\Program Files\\OpenVPN\\config\\user-pass.txt"
explicit-exit-notify 3

Все необходимые сертификаты были созданы нами ранее с помощью ssl-admin, скопируйте их с сервера. В файл «C:\Program Files\OpenVPN\config\user-pass.txt» необходимо в две строки внести имя пользователя и пароль для аутентификации на сервере OpenVPN. Конечно, это не безопасно, но ничего не поделаешь 🙁 Теперь можно запускать OpenVPN GUI и подключаться к серверу. Под ОС Windows 7 и Windows Server 2008 это необходимо делать от имени администратора.

Поделиться ссылкой:

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


Примечание - Вы можете использовать эти HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>