Прочитал топик habrahabr.ru/blogs/linux/67209 и решил выложить сюда свою статью, которая была до этого видна только в закрытой корпоративной Wiki.
Обычно, при создании VPN, используется подключение типа точка-точка к некоторому серверу, либо установка ethernet-туннеля с некоторым сервером, при котором туннелю назначается определённая подсеть. Сервер VPN при этом выполняет функции маршрутизации и фильтрования трафика для доступа к локальной сети через VPN.
Данная статья рассматривает другой подход к созданию виртуальной сети, при котором удалённые системы включаются в уже существующую локальную подсеть, а сервер VPN выполняет роль Ethernet-шлюза. При использовании такого подхода мы всё ещё имеем возможность фильтровать трафик на основании способа подключения (например, использовать для локальной сети и для удалённых пользователей разные фильтры), но исключается необходимость настройки маршрутизации, а удалённые машины включаются прямо в локальную сеть, видят ресурсы, даже способны использовать широковещательные посылки вообще без дополнительной настройки. Через такой VPN у них отображаются все компьютеры локальной сети Windows, все доступные XDMCP-серверы при XDMCP broadcast и т. д.
Предположим, что имеется офис с локальной сетью, используется IP-подсеть 192.168.168.0/24. В эту локальную сеть мы включим домашних пользователей, то есть они будут иметь адрес из этой же самой подсети. Необходимо убедиться, что у них «дома» не встречается данная подсеть, и что никакие системы в локальной сети не имеют адресов из диапазона, который мы выделим для удалённых пользователей.
Для работы такой техники нам нужны некоторые ядерные драйвера. Это универсальный драйвер виртуальных сетевых интерфейсов tun, и драйвер ethernet-моста bridge. Можно включить их в ядро, или собрать модулями:
Если они будут собраны модулями, необходимо либо включить автоматическую загрузку модулей в ядре, либо загружать их самому перед установкой VPN-соединения.
Для сервера потребуется OpenVPN и утилиты для обслуживания моста. В Gentoo они собираются следующим образом:
При использовании >=sys-apps/baselayout-1.12.6 этого достаточно, для более старых версий потребуются специальные утилиты для обслуживания tun/tap-устройств:
Положим, eth2 — интерфейс, к которому подключена локальная сеть, с назначенным адресом 192.168.168.254. Его настройка выглядела примерно так:
Поскольку он будет участвовать в мосте, ему не нужно назначать адреса. Также, в мосте участвует вновь создаваемый виртуальный интерфейс tap0, которому тоже не назначается никакого адреса. Адрес, который использовался eth2, назначается теперь мосту br0:
Также нужно создать настроечные скрипты для указанных интерфейсов:
Достаточно автоматически загружать только интерфейс br0. depend_br0() автоматически поднимет все остальные необходимые ему для работы:
Мы будем авторизовывать клиентов посредством RSA-ключей OpenSSL. Для упрощения процесса, для нас приготовили несколько init-скриптов:
Там есть файл vars, в который мы занесём общие значения:
Внизу этого файла мы заполняем наши переменные:
Загружаем переменные из этого файла и строим CA (Certificate Authority):
Для генерации ключа сервера с именем office, используем следующую команду:
На вопрос «Common Name» нужно ответить именем сервера (в нашем случае, office). На два вопроса в конце «Sign the certificate? [y/n]» и «1 out of 1 certificate requests certified, commit? [y/n]» отвечаем «y».
При необходимости, можно будет создать дополнительные ключи серверов. Например, это могут быть резервные серверы доступа для повышения надёжности системы. Они создаются той же командой, перед ней нужно выполнить source ./vars.
Здесь ничего дополнительно делать не придётся, но придётся подождать.
Этот файл нужен только на сервере.
Каждому клиенту необходимо выдать свой ключ. Для клиента с именем client ключ создаётся командой
На вопрос о «Common Name» отвечаем именем клиента (в данном случае, client). На два вопроса в конце отвечаем согласием.
Сгенерированные ключи и сертификаты передаём клиентам через защищённый канал. При необходимости, можно создавать ещё ключи той же командой. Перед её запуском, необходимо загрузить окружение — выполнить source ./vars.
Для запуска следует использовать следующую конфигурацию сервера (файл /etc/openvpn/openvpn.conf):
Ключ office.key должен иметь режим 600 (доступ только владельцу). Файлы office.crt и dh1024.pem имеют режим 644.
Поскольку мы используем мост, есть несколько особенностей организации фильтрования пакетов. Например, не все проходящие пакеты могут вообще оказаться IPv4. Для настройки работы моста в ядре существует несколько параметров:
Переменные этой группы сохраняются в файлах директории /proc/sys/net/bridge/. Их можно также настраивать в /etc/sysctl.conf, тогда они все получат префикс «net.brigde.»
Для фильтрования пакетов, проходящих через мост, используется соответствие physdev, которое различает, с какого и на какой порт моста следует пакет. Включаем его в ядре:
Кроме этого, конфигурация ядра должна разрешать передачу пакетов на фильтрацию iptables, т.е. bridge-nf-call-iptables=1 и bridge-nf-call-ip6tables=1 (если вы используете IPv6).
После можете использовать, например, такие правила для фильтрования:
Поподробнее про настройку фильтрации между портами поста можно почитать в статье Building bridges with Linux
Если вы не хотите делать никаких различий между пользователями LAN и пользователями bridged VPN, вы можете просто выключить эти параметры в ядре (они включены по умолчанию):
На клиенте необходимо создать конфигурационный файл OpenVPN следующего содержания:
Если сервер подключен через несколько провайдеров, можно повысить устойчивость сети к отказам. Для этого клиенту нужно прописать несколько опций remote, по одной на сервер, в порядке «сначала предпочтительные».
Имена файлов, указанные в параметрах ca, cert и key — это файлы, переданные через защищённый канал. Права доступа к файлу key должны быть установлены в 600.
Необходим universal tun/tap driver в ядре, либо модулем, но загруженный.
При установке net-misc/openvpn создаётся скрипт /etc/init.d/openvpn. Этот скрипт запускает openvpn с конфигурационным файлом /etc/openvpn/openvpn.conf. Мы, однако, можем поддерживать несколько конфигураций OpenVPN одновременно, если сделаем симлинки вида /etc/init.d/openvpn.network-name -> /etc/init.d/openvpn — каждый такой скрипт запускает OpenVPN с конфигурационным файлом /etc/openvpn/network-name.conf.
Соответственно, помещаем туда вышеприведённый конфиг, создаём симлинк и кладём скрипты в поддиректорию в /etc/openvpn/. В конфиге прописываем полный путь к ключу и сертификатам. Следите, чтобы имена файлов в конфиге не пересекались, во избежание неприятных эффектов!
Запуск и останов сети производятся через управление сервисом /etc/openvpn.network-name.
Конфигурационный файл помещается в директорию «C:\Program Files\OpenVPN\config\» с именем вроде «office.ovpn», туда же помещаются остальные файлы — ключи и сертификаты. Если мы их помещаем в поддиректорию (например, хотим использовать несколько виртуальных сетей и все они предоставили файлы с одинаковым именем ca.crt), указываем полные пути к файлам.
Для запуска сетей можно либо запустить сервис OpenVPN (тогда будут запущены все конфигурации *.ovpn, найденные в config\), либо по отдельности — щёлкаем по файлу .ovpn правой кнопкой и выбираем «Запустить OpenVPN с этой конфигурацией».
Проверить доступность сервера, если он запущен на TCP, можно обычным telnetом.
По логу OpenVPN видно, что клиент успешно присоединился к серверу, авторизовался, но не смог привязать виртуальную сеть к виртуальному адаптеру. Скорее всего, какие-то другие процессы уже задествовали все имеющиеся в системе адаптеры TAP-Win32. Это мог быть и сам OpenVPN, повисший и не отдавший адаптер.
Лечится перезагрузкой или выяснением, какие бы это могли быть процессы и принудительным их убиванием.
При написании данной статьи, использовались следующие источники:
P.S. Некоторые источники почили. Ссылки я убирать не буду, но стоит иметь ввиду.
Обычно, при создании VPN, используется подключение типа точка-точка к некоторому серверу, либо установка ethernet-туннеля с некоторым сервером, при котором туннелю назначается определённая подсеть. Сервер VPN при этом выполняет функции маршрутизации и фильтрования трафика для доступа к локальной сети через VPN.
Данная статья рассматривает другой подход к созданию виртуальной сети, при котором удалённые системы включаются в уже существующую локальную подсеть, а сервер VPN выполняет роль Ethernet-шлюза. При использовании такого подхода мы всё ещё имеем возможность фильтровать трафик на основании способа подключения (например, использовать для локальной сети и для удалённых пользователей разные фильтры), но исключается необходимость настройки маршрутизации, а удалённые машины включаются прямо в локальную сеть, видят ресурсы, даже способны использовать широковещательные посылки вообще без дополнительной настройки. Через такой VPN у них отображаются все компьютеры локальной сети Windows, все доступные XDMCP-серверы при XDMCP broadcast и т. д.
Структура сети и настройка сервера
Предположим, что имеется офис с локальной сетью, используется IP-подсеть 192.168.168.0/24. В эту локальную сеть мы включим домашних пользователей, то есть они будут иметь адрес из этой же самой подсети. Необходимо убедиться, что у них «дома» не встречается данная подсеть, и что никакие системы в локальной сети не имеют адресов из диапазона, который мы выделим для удалённых пользователей.
Поддержка моста в ядре
Для работы такой техники нам нужны некоторые ядерные драйвера. Это универсальный драйвер виртуальных сетевых интерфейсов tun, и драйвер ethernet-моста bridge. Можно включить их в ядро, или собрать модулями:
-> Networking -> Networking support (NET [=y]) -> Networking options <*> 802.1d Ethenet Bridging (BRIDGE [=y]) -> Device Drivers -> Network device support (NETDEVICES [=y]) <*> Universal TUN/TAP device driver support (TUN [=y])
Если они будут собраны модулями, необходимо либо включить автоматическую загрузку модулей в ядре, либо загружать их самому перед установкой VPN-соединения.
Программное обеспечение
Для сервера потребуется OpenVPN и утилиты для обслуживания моста. В Gentoo они собираются следующим образом:
emerge net-misc/bridge-utils net-misc/openvpn
При использовании >=sys-apps/baselayout-1.12.6 этого достаточно, для более старых версий потребуются специальные утилиты для обслуживания tun/tap-устройств:
emerge sys-apps/usermode-utilities
Настройка сети
Положим, eth2 — интерфейс, к которому подключена локальная сеть, с назначенным адресом 192.168.168.254. Его настройка выглядела примерно так:
config_eth2=( "192.168.168.254/24" )
Поскольку он будет участвовать в мосте, ему не нужно назначать адреса. Также, в мосте участвует вновь создаваемый виртуальный интерфейс tap0, которому тоже не назначается никакого адреса. Адрес, который использовался eth2, назначается теперь мосту br0:
config_eth2=( "null" ) tuntap_tap0="tap" config_tap0=( "null" ) depend_br0() { need net.tap0 net.eth2 } # указываем существующие интерфейсы, объединяя их в мост bridge_br0="eth2 tap0" # либо, можно динамически подключать туда вновь появляющиеся интерфейсы #bridge_add_eth2="br0" config_br0=( "192.168.168.254/24" )
Также нужно создать настроечные скрипты для указанных интерфейсов:
cd /etc/init.d ln -s net.lo net.eth2 ln -s net.lo net.tap0 ln -s net.lo net.br0
Достаточно автоматически загружать только интерфейс br0. depend_br0() автоматически поднимет все остальные необходимые ему для работы:
rc-update add net.br0 default /etc/init.d/net.eth2 stop /etc/init.d/net.br0 start
Создание ключей OpenVPN
Мы будем авторизовывать клиентов посредством RSA-ключей OpenSSL. Для упрощения процесса, для нас приготовили несколько init-скриптов:
cd /usr/share/openvpn/easy-rsa/
Там есть файл vars, в который мы занесём общие значения:
nano vars
Внизу этого файла мы заполняем наши переменные:
export KEY_COUNTRY="RU" export KEY_PROVINCE="Voronezh oblast" export KEY_CITY="Boguchar" export KEY_ORG="OrganiZationnAme" export KEY_EMAIL="root@oza.ru"
Загружаем переменные из этого файла и строим CA (Certificate Authority):
source ./vars ./clean-all ./build-ca
Ключ сервера
Для генерации ключа сервера с именем office, используем следующую команду:
./build-key-server office
На вопрос «Common Name» нужно ответить именем сервера (в нашем случае, office). На два вопроса в конце «Sign the certificate? [y/n]» и «1 out of 1 certificate requests certified, commit? [y/n]» отвечаем «y».
При необходимости, можно будет создать дополнительные ключи серверов. Например, это могут быть резервные серверы доступа для повышения надёжности системы. Они создаются той же командой, перед ней нужно выполнить source ./vars.
Параметры Диффи-Хеллмана
Здесь ничего дополнительно делать не придётся, но придётся подождать.
./build-dh
Этот файл нужен только на сервере.
Ключи клиентов
Каждому клиенту необходимо выдать свой ключ. Для клиента с именем client ключ создаётся командой
./build-key client
На вопрос о «Common Name» отвечаем именем клиента (в данном случае, client). На два вопроса в конце отвечаем согласием.
Сгенерированные ключи и сертификаты передаём клиентам через защищённый канал. При необходимости, можно создавать ещё ключи той же командой. Перед её запуском, необходимо загрузить окружение — выполнить source ./vars.
Настройка и запуск сервиса OpenVPN
Для запуска следует использовать следующую конфигурацию сервера (файл /etc/openvpn/openvpn.conf):
# Этот порт рекомендован IANA для OpenVPN. Можно перевесить на другой порт, но секретность не повысится - он всё равно первым делом признаётся, что он - OpenPVN. port 1194 # OpenVPN может использовать tcp и udp в качестве транспортного протокола, udp - предпочтительнее proto udp # Виртуальный интерфейс, который мы включили в мост, непременно типа tap (через tun нельзя эмулировать Ethernet) dev tap0 # Корневой самоподписанный сертификат CA ca /etc/openvpn/keys/ca.crt # Сертификат и секретный ключ сервера. crt должен иметь режимы 644, key - 600 cert /etc/openvpn/keys/office.crt key /etc/openvpn/keys/office.key # Файл с параметрами Диффи-Хеллмана. Если у вас другая длина ключей, исправьте имя :) dh /etc/openvpn/keys/dh1024.pem # Раздавать удалённым клиентам адреса в этой подсети, из этого диапазона (обратите внимание - подсеть задаётся ВСЯ, как в конфиге сетевухи, а диапазон - часть подсети) server-bridge 192.168.168.254 255.255.255.0 192.168.168.128 192.168.168.159 # Разрешить взаимодействие клиентов друг с другом (иначе только с сервером и сегментом сети "за мостом") client-to-client # Это позволит выдать клиенту тот же самый адрес, какой выдавали раньше, если не занят ifconfig-pool-persist /etc/openvpn/ipp.txt # Если вы не хотите через DHCP передавать также и адрес DNS-сервера, можно убрать следующую строку push "dhcp-option DNS 192.168.168.254" # Компрессия comp-lzo # Максимальное число клиентов - имеет смысл сделать меньше или равно числу адресов в диапазоне server-bridge max-clients 32 # Подробности относительно этих ключей - в документации OpenVPN keepalive 10 120 # Не переинициализировать tun и не перечитывать ключ при переподключениях; если работаем не как root, а как nobody, то нам это и не позволят, поэтому либо все эти опции, либо ни одну из них user nobody group nobody persist-key persist-tun # Каждую минуту OpenVPN сбрасывает сюда текущее состояние (список клиентов, маршруты и т. д.) status /tmp/openvpn-status.log # Очень шумный лог, нормальная работа - verb 2 verb 6 log-append /var/log/openvpn.log
Ключ office.key должен иметь режим 600 (доступ только владельцу). Файлы office.crt и dh1024.pem имеют режим 644.
Настройка фильтрования
Поскольку мы используем мост, есть несколько особенностей организации фильтрования пакетов. Например, не все проходящие пакеты могут вообще оказаться IPv4. Для настройки работы моста в ядре существует несколько параметров:
Переменные этой группы сохраняются в файлах директории /proc/sys/net/bridge/. Их можно также настраивать в /etc/sysctl.conf, тогда они все получат префикс «net.brigde.»
- bridge-nf-call-arptables
Логическая переменная bridge-nf-call-arptables управляет передачей трафика ARP в цепочку FORWARD пакетного фильтра arptables. Установленное по умолчанию значение 1 разрешает передачу пакетов фильтрам, 0 – запрещает. - bridge-nf-call-iptables
Логическая переменная bridge-nf-call-iptables управляет передачей проходящего через мост трафика IPv4 в цепочки iptables. Используемое по умолчанию значение 1 разрешает передачу пакетов для фильтрации, 0 – запрещает. - bridge-nf-call-ip6tables
Действие аналогично предыдущему, только оно настраивает передачу трафика IPv6 для фильтрования в цепочки ip6tables. - bridge-nf-filter-vlan-tagged
Логическая переменная bridge-nf-filter-vlan-tagged определяет возможность передачи трафика IP/ARP с тегами VLAN программам фильтрации пакетов (arptables/iptables). Значение 1 (установлено по умолчанию) разрешает передачу пакетов с тегами VLAN программам фильтрации, 0 – запрещает.
Для фильтрования пакетов, проходящих через мост, используется соответствие physdev, которое различает, с какого и на какой порт моста следует пакет. Включаем его в ядре:
-> Networking -> Networking support (NET [=y]) -> Networking options -> Network packet filtering framework (Netfilter) (NETFILTER [=y]) -> Core Netfilter Configuration -> Netfilter Xtables support (required for ip_tables) (NETFILTER_XTABLES [=y]) -> "physdev" match support (NETFILTER_XT_MATCH_PHYSDEV [=y])
Кроме этого, конфигурация ядра должна разрешать передачу пакетов на фильтрацию iptables, т.е. bridge-nf-call-iptables=1 и bridge-nf-call-ip6tables=1 (если вы используете IPv6).
После можете использовать, например, такие правила для фильтрования:
iptables -A FORWARD -p tcp --dport 22 -m physdev --physdev-in eth1 --physdev-out eth0 -j ACCEPT
Поподробнее про настройку фильтрации между портами поста можно почитать в статье Building bridges with Linux
Если вы не хотите делать никаких различий между пользователями LAN и пользователями bridged VPN, вы можете просто выключить эти параметры в ядре (они включены по умолчанию):
echo "net.bridge.bridge-nf-call-iptables = 0" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-ip6tables = 0" >> /etc/sysctl.conf
Клиенты
На клиенте необходимо создать конфигурационный файл OpenVPN следующего содержания:
client nobind dev tap proto udp # Куда подключаться. Можно указать несколько опций remote - будет использоваться первый доступный сервер. Если для server.example.net имеется несколько A-записей, между ними выбор производится случайно. remote server.example.net 1194 # Никогда не сдаваться, пытаться подключаться бесконечно. resolv-retry infinite # Либо все опции вместе, либо ни одна из них persist-key persist-tun user nobody group nogroup comp-lzo ns-cert-type server ca ca.crt cert client.crt key client.key
Если сервер подключен через несколько провайдеров, можно повысить устойчивость сети к отказам. Для этого клиенту нужно прописать несколько опций remote, по одной на сервер, в порядке «сначала предпочтительные».
Имена файлов, указанные в параметрах ca, cert и key — это файлы, переданные через защищённый канал. Права доступа к файлу key должны быть установлены в 600.
Linux
Необходим universal tun/tap driver в ядре, либо модулем, но загруженный.
Gentoo
При установке net-misc/openvpn создаётся скрипт /etc/init.d/openvpn. Этот скрипт запускает openvpn с конфигурационным файлом /etc/openvpn/openvpn.conf. Мы, однако, можем поддерживать несколько конфигураций OpenVPN одновременно, если сделаем симлинки вида /etc/init.d/openvpn.network-name -> /etc/init.d/openvpn — каждый такой скрипт запускает OpenVPN с конфигурационным файлом /etc/openvpn/network-name.conf.
Соответственно, помещаем туда вышеприведённый конфиг, создаём симлинк и кладём скрипты в поддиректорию в /etc/openvpn/. В конфиге прописываем полный путь к ключу и сертификатам. Следите, чтобы имена файлов в конфиге не пересекались, во избежание неприятных эффектов!
Запуск и останов сети производятся через управление сервисом /etc/openvpn.network-name.
Windows
Конфигурационный файл помещается в директорию «C:\Program Files\OpenVPN\config\» с именем вроде «office.ovpn», туда же помещаются остальные файлы — ключи и сертификаты. Если мы их помещаем в поддиректорию (например, хотим использовать несколько виртуальных сетей и все они предоставили файлы с одинаковым именем ca.crt), указываем полные пути к файлам.
Для запуска сетей можно либо запустить сервис OpenVPN (тогда будут запущены все конфигурации *.ovpn, найденные в config\), либо по отдельности — щёлкаем по файлу .ovpn правой кнопкой и выбираем «Запустить OpenVPN с этой конфигурацией».
Возможные проблемы
Проверить доступность сервера, если он запущен на TCP, можно обычным telnetом.
Windows
Нет свободного виртуального адаптера TAP
Wed Dec 31 10:43:51 2008 TCP connection established with 88.83.201.253:1194 Wed Dec 31 10:43:51 2008 TCPv4_CLIENT link local: [undef] Wed Dec 31 10:43:51 2008 TCPv4_CLIENT link remote: 88.83.201.253:1194 Wed Dec 31 10:44:51 2008 TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity) Wed Dec 31 10:44:51 2008 TLS Error: TLS handshake failed Wed Dec 31 10:44:51 2008 Fatal TLS error (check_tls_errors_co), restarting Wed Dec 31 10:44:51 2008 SIGUSR1[soft,tls-error] received, process restarting Wed Dec 31 10:44:56 2008 IMPORTANT: OpenVPN's default port number is now 1194, based on an official port number assignment by IANA. OpenVPN 2.0-beta16 and earlier used 5000 as the default port. Wed Dec 31 10:44:56 2008 Re-using SSL/TLS context Wed Dec 31 10:44:56 2008 LZO compression initialized Wed Dec 31 10:44:56 2008 Attempting to establish TCP connection with 88.83.201.253:1194 Wed Dec 31 10:44:56 2008 TCP connection established with 88.83.201.253:1194 Wed Dec 31 10:44:56 2008 TCPv4_CLIENT link local: [undef] Wed Dec 31 10:44:56 2008 TCPv4_CLIENT link remote: 88.83.201.253:1194 Wed Dec 31 10:45:11 2008 [office] Peer Connection Initiated with 88.83.201.253:1194 Wed Dec 31 10:45:13 2008 All TAP-Win32 adapters on this system are currently in use. Wed Dec 31 10:45:13 2008 Exiting Press any key to continue...
По логу OpenVPN видно, что клиент успешно присоединился к серверу, авторизовался, но не смог привязать виртуальную сеть к виртуальному адаптеру. Скорее всего, какие-то другие процессы уже задествовали все имеющиеся в системе адаптеры TAP-Win32. Это мог быть и сам OpenVPN, повисший и не отдавший адаптер.
Лечится перезагрузкой или выяснением, какие бы это могли быть процессы и принудительным их убиванием.
Ссылки
При написании данной статьи, использовались следующие источники:
- Gentoo Linux Wiki — HOWTO OpenVPN Server for Ethenet Bridging with Server Certificates (Есть копия этой страницы, по адресу: http://www.gentoo-wiki.info/HOWTO_OpenVPN_Server_for_Ethernet_Bridging_with_Server_Certificates. Спасибо hexes за ссылку!)
- Gentoo Linux Wiki — HOWTO OpenVPN Linux Server Windows Client
- OpenVPN Documentation — HOWTO
- Энциклопедия сетевых протоколов — параметры sysctl для стека IP
- Building bridges with Linux
P.S. Некоторые источники почили. Ссылки я убирать не буду, но стоит иметь ввиду.