Предположим, что вы работаете на шлюзе сети #1 (с публичным адресом A.B.C.D, приватным адресом 192.168.1.1) и
запускаете ping 192.168.2.1, т.е. на приватный адрес машины с IP
адресом W.X.Y.Z. Что должно произойти, чтобы это сработало?
-
Шлюз должен знать, как достичь 192.168.2.1. Другими словами, у
него должен быть маршрут к 192.168.2.1.
-
Приватные IP адреса, такие как диапазон 192.168.x не
адресуются в интернет. Каждый пакет, отправляемый на 192.168.2.1
должен быть ``завернут'' в другой пакет. Исходным адресом пакета должен быть A.B.C.D, а адресом назначения W.X.Y.Z. Этот
процесс называется инкапсуляцией.
-
Как только этот пакет достигнет W.X.Y.Z, необходимо будет
``разинкапсулировать'' его и доставить к 192.168.2.1.
Как вы можете увидеть, это требует ``туннеля'' между двумя сетями. Два конца
``туннеля'' это IP адреса A.B.C.D и W.X.Y.Z. Туннель используется для передачи трафика с приватными IP
адресами через интернет.
В FreeBSD этот туннель создается с помощью устройства generic interface, или gif. Как вы можете догадаться, интерфейс gif на каждом хосте должен быть настроен с четырьмя IP адресами;
два для публичных IP адресов и два для приватных IP адресов.
В ядро обеих компьютеров FreeBSD должна быть встроена поддержка устройства gif. Вы
можете сделать это, добавив строку:
pseudo-device gif
к файлу настройки ядра на обеих компьютерах, с последующей компиляцией, установкой и
перезагрузкой.
Настройка туннеля это двухшаговый процесс. Во-первых, необходимо задать сведения о
внешнем (или публичном) IP адресе с помощью gifconfig(8). Затем о
приватном IP адресе с помощью ifconfig(8).
На шлюзе сети #1 для настройки туннеля вам потребуется запустить следующие две
команды.
gifconfig gif0 A.B.C.D W.X.Y.Z
ifconfig gif0 inet 192.168.1.1 192.168.2.1 netmask 0xffffffff
На другом шлюзе подобные команды, но с IP адресами в обратном порядке.
gifconfig gif0 W.X.Y.Z A.B.C.D
ifconfig gif0 inet 192.168.2.1 192.168.1.1 netmask 0xffffffff
Затем вы можете запустить:
gifconfig gif0
для просмотра настройки. Например, на шлюзе сети #1 вы увидите:
# gifconfig gif0
gif0: flags=8011<UP,POINTTOPOINT,MULTICAST> mtu 1280
inet 192.168.1.1 --> 192.168.2.1 netmask 0xffffffff
physical address inet A.B.C.D --> W.X.Y.Z
Как вы можете видеть, был создан туннель между физическими адресами A.B.C.D и W.X.Y.Z, для тунеллирования
разрешен трафик между 192.168.1.1 и 192.168.2.1.
Это также добавляет запись к таблице маршрутизации на обеих машинах, вы можете
проверить запись командой netstat -rn. Вот вывод этой команды на
шлюзе сети #1.
# netstat -rn
Routing tables
Internet:
Destination Gateway Flags Refs Use Netif Expire
...
192.168.2.1 192.168.1.1 UH 0 0 gif0
...
Как показывает значение поля ``Flags'', это маршрут к хосту, что означает, что каждый
шлюз знает, как достичь другого шлюза, но не знает как достичь остальной части
соответствующей сети. Эта проблема будет быстро решена.
Вероятно, на обеих машинах запущен межсетевой экран. VPN должен обходить его. Вы
можете разрешить весь трафик между двумя сетями, или включить правила, защищающие каждый
конец соединения от другого.
Это сильно упрощает тестирование настройки межсетевого экрана, если вы разрешаете весь
трафик через VPN. Вы всегда можете Вы всегда можете усилить защиту позже. Если вы
используете на шлюзах ipfw(8), команда вроде
этой
ipfw add 1 allow ip from any to any via gif0
разрешит весь трафик между двумя концами VPN без влияния на другие правила межсетевого
экрана. Очевидно, вам потребуется запустить эту команду на обеих шлюзах.
Этого достаточно для включения ping с одного шлюза на другой. На 192.168.1.1, вы сможете запустить
ping 192.168.2.1
и получить ответ, и аналогично на другом шлюзе.
Однако, машины в другой сети пока недоступны. Это из-за маршрутизации -- хотя шлюзы
знают, как связаться друг с другом, они не знают, как связаться с сетью за другим
шлюзом.
Для решения этой проблемы вы должны добавить статический маршрут на каждом шлюзе.
Команда на первом шлюзе будет выглядеть так:
route add 192.168.2.0 192.168.2.1 netmask 0xffffff00
Она говорит ``Для достижения хостов в сети 192.168.2.0,
отправляйте пакеты хосту 192.168.2.1''. Вам потребуется запустить
похожую команду на другом шлюзе, но с адресами 192.168.1.x.
IP трафик с хостов в одной сети теперь может достичь хосты в другой сети.
Теперь создано две трети VPN между двумя сетями, поскольку это ``виртуальная
(virtual)'' ``сеть (network)''. Она еще не приватная (private). Вы можете протестировать
ее с помощью ping(8) и tcpdump(1). Войдите на
шлюз и запустите
tcpdump dst host 192.168.2.1
В другой сессии на этом же хосте запустите
ping 192.168.2.1
Вы увидите примерно такие строки:
16:10:24.018080 192.168.1.1 > 192.168.2.1: icmp: echo request
16:10:24.018109 192.168.1.1 > 192.168.2.1: icmp: echo reply
16:10:25.018814 192.168.1.1 > 192.168.2.1: icmp: echo request
16:10:25.018847 192.168.1.1 > 192.168.2.1: icmp: echo reply
16:10:26.028896 192.168.1.1 > 192.168.2.1: icmp: echo request
16:10:26.029112 192.168.1.1 > 192.168.2.1: icmp: echo reply
Как вы видите, ICMP сообщения пересылаются вперед и назад незашифрованными. Если вы
использовали с tcpdump(1) параметр
-s для получения большего объема данных пакета, то увидите
больше информации.
Конечно же это неприемлемо. В следующем разделе мы обсудим защиту соединения между
двумя сетями, так что весь трафик будет автоматически шифроваться.
Резюме:
-
Настройте оба ядра с ``pseudo-device gif''.
-
Отредактируйте /etc/rc.conf на шлюзе #1 и добавьте следующие
строки (подставляя IP адреса где необходимо).
gifconfig_gif0="A.B.C.D W.X.Y.Z"
ifconfig_gif0="inet 192.168.1.1 192.168.2.1 netmask 0xffffffff"
static_routes="vpn"
route_vpn="192.168.2.0 192.168.2.1 netmask 0xffffff00"
-
Отредактируйте скрипт межсетевого экрана (/etc/rc.firewall,
или подобный) на обеих хостах и добавьте
ipfw add 1 allow ip from any to any via gif0
-
Выполните соответствующие изменения в /etc/rc.conf на шлюзе
#2, меняя порядок IP адресов.
Для защиты соединения мы будем использовать IPsec. IPsec предоставляет хостам механизм
определения ключа для шифрования и для последующего использования этого ключа для
шифрования данных между двумя хостами.
Здесь будут рассмотрены два аспекта настройки.
-
У хостов должен быть способ согласования используемого алгоритма шифрования. Как
только хосты договорятся об этом, можно говорить об установленном между ними ``безопасном
соединении''.
-
Должен быть механизм определения, какой трафик необходимо шифровать. Конечно, вам не
требуется шифровать весь исходящий трафик -- достаточно шифровать только трафик, идущий
через VPN. Правила, определяющие то, какой трафик необходимо шифровать, называются
``политикой безопасности''.
Безопасное соединение и политика безопасности поддерживаются ядром, и могут быть
изменены программами пользователя. Однако перед тем, как вы сможете сделать это,
необходимо настроить поддержку протоколов IPsec и Encapsulated Security Payload (ESP) в
ядре. Это делается добавлением в настройку ядра параметров:
options IPSEC
options IPSEC_ESP
с последующим перекомпилированием, переустановкой и перезагрузкой. Как и прежде вам
потребуется сделать это с ядрами на обеих шлюзах.
При настройке параметров безопасности (security associations) у вас есть два варианта.
Вы можете настроить их вручную для обеих хостов, задав алгоритм шифрования, ключи для
шифрования и так далее, или использовать даемоны, реализующие Internet Key Exchange
protocol (IKE), который сделает это за вас.
Рекомендуется последнее. Помимо прочего, этот способ более прост.
Редактирование и отображение политики безопасности выполняется с помощью setkey(8). По
аналогии, setkey используется для настройки таблиц политики
безопасности ядра так же, как route(8) используется
для настройки таблиц маршрутизации ядра. setkey также может
отображать текущие параметры безопасности, и продолжая аналогию дальше, это соответствует
netstat -r.
Существует множество даемонов для управления параметрами безопасности в FreeBSD. Здесь
будет описано использование одного из них, racoon. racoon находится в категории security/
коллекции портов FreeBSD и устанавливается обычным способом.
racoon должен работать на обеих шлюзах. На каждом из хостов он настраивается с IP
адресом другого конца VPN, и секретным ключом (по вашему выбору, должен быть одним и тем
же на обеих шлюзах).
Эти два даемона подключаются друг к другу, подтверждают, что они именно те, за кого
себя выдают (используя секретный ключ, заданный вами). Затем даемоны генерируют новый
секретный ключ и используют его для шифрования трафика через VPN. Они периодически
изменяют этот ключ, так что даже если атакующий сломает один из ключей (что теоретически
почти невозможно) это не даст ему слишком много -- он сломал ключ, который два даемона
уже сменили на другой.
Настройки racoon сохраняются в ${PREFIX}/etc/racoon. Этот
файл не требует слишком больших изменений. Другим компонентом настройки racoon, который
потребуется изменить, является ``предварительный ключ''.
В настройке по умолчанию racoon ищет его в файле ${PREFIX}/etc/racoon/psk.txt. Необходимо отметить, что
предварительный ключ не
используется для шифрования трафика через VPN соединение это просто маркер, позволяющий
управляющим ключами даемонам доверять друг другу.
psk.txt содержит строку для каждого удаленного сервера, с
которым происходит соединение. В этом примере два сервера, каждый файл psk.txt будет содержать одну строку (каждый конец VPN общается
только с другим концом.
На шлюзе #1 эта строка будет выглядеть примерно так:
W.X.Y.Z secret
То есть публичный IP адрес
удаленной стороны, пробел и текстовая строка, секретная фраза.
На шлюзе #2 строка будет выглядеть примерно так:
A.B.C.D secret
То есть публичный IP адрес удаленной стороны и та же секретная фраза. Перед запуском
racoon режим доступа к файлу psk.txt должен быть установлен в
0600 (т.е. запись и чтение только для root).
Вы должны запустить racoon на обеих шлюзах. Вам также потребуется добавить правила для
включения IKE трафика, передающегося по UDP через порт ISAKMP (Internet Security
Association Key Management Protocol). Опять же, они должны быть расположены насколько
возможно ближе к началу набора правил.
ipfw add 1 allow udp from A.B.C.D to W.X.Y.Z isakmp
ipfw add 1 allow udp from W.X.Y.Z to A.B.C.D isakmp
Как только racoon будет запущен, вы можете попробовать выполнить ping с одного шлюза
на другой. Соединение все еще не зашифровано, но racoon установит параметры безопасности
между двумя хостами -- это может занять время и вы можете заметить небольшую задержку
перед началом ответа команды ping.
Как только параметры безопасности установлены, вы можете просмотреть их используя setkey(8).
Запустите
setkey -D
на любом из хостов для просмотра информации о параметрах безопасности.
Это одна сторона проблемы. Другая сторона это настройка политики безопасности.
Для создания разумной политики безопасности давайте вспомним, что уже было настроено.
Это рассмотрение относится к обеим концам соединения.
Каждый отправляемый IP пакет имеет заголовок, содержащий информацию о пакете.
Заголовок включает IP адреса источника и назначения. Как мы уже знаем, приватные IP
адреса, такие как 192.168.x.y, не могут появиться в интернет. Они
должны быть сначала включены внутрь другого пакета. В этом пакете приватные IP адреса
источника и назначения заменяются публичными IP адресами.
То есть исходящий пакет, который выглядит примерно так:
будет инкапсулирован в другой пакет, выглядящий примерно так:
Этой инкапсуляцией занимается устройство gif. Как вы
можете видеть, теперь у пакета есть реальный IP адрес, исходный пакет был включен в этот
пакет в виде данных, которые передаются через интернет.
Конечно, мы хотим зашифровать весь трафик между VPN. Вы можете сформулировать это на
словах так:
``Если пакет отправляется с A.B.C.D, и предназначен для W.X.Y.Z, расшифровать его, используя необходимые параметры
безопасности.''
``Если пакет отправляется с W.X.Y.Z, и предназначен для A.B.C.D, расшифровать его, используя необходимые параметры
безопасности.''
Это похоже на желаемое, но не совсем то. Если вы сделаете это, весь трафик от и к W.X.Y.Z, даже если он не является частью VPN, будет зашифрован.
Правильная политика такова:
``Если пакет отправляется с A.B.C.D, в нем инкапсулирован
другой пакет и адрес назначения W.X.Y.Z, зашифровать его,
используя необходимые параметры безопасности.''
``Если пакет отправляется с W.X.Y.Z, в нем инкапсулирован
другой пакет и адрес назначения A.B.C.D, зашифровать его,
используя необходимые параметры безопасности.''
Тонкое, но необходимое различие.
Политика безопасности также устанавливается с использованием setkey(8). В setkey(8) предусмотрен
язык определения политики setkey(8). Вы можете
или ввести инструкции по настройке со стандартного ввода, или использовать параметр -f для задания файла, содержащего эти инструкции.
Настройка на шлюзе #1 (где есть публичный IP адрес A.B.C.D)
для включения шифрования всего предназначенного W.X.Y.Z
трафика:
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P out ipsec esp/tunnel/A.B.C.D-W.X.Y.Z/require;
Поместите эти команды в файл (например, /etc/ipsec.conf) и
запустите
# setkey -f /etc/ipsec.conf
spdadd указывает setkey(8) добавить
правило к базе данных политики безопасности. Остальная часть строки указывает какие
пакеты будут соответствовать политике. A.B.C.D/32 и W.X.Y.Z/32 это IP адреса и сетевые маски, определяющие сети или
хосты, к которым будет применяться данная политика. В данном случае мы хотим применить их
к трафику между этими двумя хостами. Параметр ipencap сообщает
ядру, что эта политика должна применяться только к пакетам, инкапсулирующим другие
пакеты. Параметр -P out сообщает, что эта политика применяется
к исходящим пакетам, и ipsec -- то, что пакеты будут
зашифрованы.
Оставшаяся часть строки определяет, как эти пакеты будут зашифрованы. Будет
использоваться протокол esp, а параметр tunnel показывает, что пакет в дальнейшем будет инкапсулирован в
IPsec пакет. Повторное использование A.B.C.D и W.X.Y.Z предназначено для выбора используемых параметров
безопасности, и наконец параметр require разрешает шифрование
пакетов, попадающих под это правило.
Это правило соответствует только исходящим пакетам. Вам потребуется похожее правило,
соответствующее входящим пакетам.
spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P in ipsec esp/tunnel/W.X.Y.Z-A.B.C.D/require;
Обратите внимание, что вместо in используется out и IP адреса переставлены.
Другому шлюзу (с публичным IP адресом W.X.Y.Z) потребуются
похожие правила.
spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P out ipsec esp/tunnel/W.X.Y.Z-A.B.C.D/require;
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P in ipsec esp/tunnel/A.B.C.D-W.X.Y.Z/require;
Наконец, вам потребуется добавить правила к межсетевому экрану для включения
прохождения пакетов ESP и IPENCAP в обе стороны. На обеих хостах потребуется добавить
следующие правила:
ipfw add 1 allow esp from A.B.C.D to W.X.Y.Z
ipfw add 1 allow esp from W.X.Y.Z to A.B.C.D
ipfw add 1 allow ipencap from A.B.C.D to W.X.Y.Z
ipfw add 1 allow ipencap from W.X.Y.Z to A.B.C.D
Поскольку правила симметричны, можно использовать их без изменения на обеих хостах
Исходящие пакеты теперь будут выглядеть примерно так:
Когда эти пакеты будут получены на удаленном конце VPN соединения, они будут
расшифрованы (используя параметры безопасности, о которых договорился racoon). Затем они
будут переданы интерфейсу gif, который ``развернет'' второй
слой, оставив пакет с внутренними адресами, который сможет попасть во внутреннюю
сеть.
Вы можете проверить безопасность тем же ping(8), который
использовался ранее. Сначала войдите на шлюз A.B.C.D и
запустите:
tcpdump dst host 192.168.2.1
В другой сессии на том же хосте запустите
ping 192.168.2.1
В этот момент вы должны увидеть примерно это:
XXX tcpdump output
Теперь, как видите, tcpdump(1) показывает
ESP пакеты. Если вы попытаетесь просмотреть их с параметром -s,
то вероятно увидите нечто непонятное, поскольку применяется шифрование.
Поздравляем. Вы только что настроили VPN между двумя удаленными сетями.
Резюме
-
Настройте оба ядра с:
options IPSEC
options IPSEC_ESP
-
Установите security/racoon. Отредактируйте ${PREFIX}/etc/racoon/psk.txt на обеих шлюзах, добавив запись для
каждого IP адреса удаленного хоста и секретный ключ, который будет известен им обеим.
Убедитесь, что режим доступа к файлу 0600.
-
Добавьте к /etc/rc.conf на каждом хосте следующие
строки:
ipsec_enable="YES"
ipsec_file="/etc/ipsec.conf"
-
Создайте /etc/ipsec.conf на каждом хосте с необходимыми
строками spdadd. На шлюзе #1 он будет таким:
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P out ipsec
esp/tunnel/A.B.C.D-W.X.Y.Z/require;
spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P in ipsec
esp/tunnel/W.X.Y.Z-A.B.C.D/require;
А на шлюзе #2 таким:
spdadd W.X.Y.Z/32 A.B.C.D/32 ipencap -P out ipsec
esp/tunnel/W.X.Y.Z-A.B.C.D/require;
spdadd A.B.C.D/32 W.X.Y.Z/32 ipencap -P in ipsec
esp/tunnel/A.B.C.D-W.X.Y.Z/require;
-
Добавьте правила к межсетевым экранам обеих хостов для включения IKE, ESP и IPENCAP
трафика:
ipfw add 1 allow udp from A.B.C.D to W.X.Y.Z isakmp
ipfw add 1 allow udp from W.X.Y.Z to A.B.C.D isakmp
ipfw add 1 allow esp from A.B.C.D to W.X.Y.Z
ipfw add 1 allow esp from W.X.Y.Z to A.B.C.D
ipfw add 1 allow ipencap from A.B.C.D to W.X.Y.Z
ipfw add 1 allow ipencap from W.X.Y.Z to A.B.C.D
Двух приведенных шагов должно быть достаточно для настройки и включения VPN. Машины в
каждой сети смогут обращаться друг к другу по IP адресам, и весь трафик через соединение
будет автоматически надежно зашифрован.