Соединяем два сервера FreeBSD по IPSec

Забегая немного вперед скажу что задачей было соединить 2 сервера с FreeBSD для безопасной передачи данных через Интернет.
Для полноты картины задам внешние и внутренние IP адреса для обоих серверов
srv1 — 177.111.22.33
srv2 — 100.200.100.200
Я начал с обновления обоих серверов с помощью команд

freebsd-update fetch install
portsnap fetch update
portupgrade -arR

но это необязательная процедура. После обновления нам нужно включить поддержку IPSec в ядре так как по умолчанию она выключена. Для этого выясняем архитектуру ОС командой uname -a (в моем случае amd64) и топаем в такую директорию:

root@srv1:~# cd /usr/src/sys/amd64/conf/

Если система ругнулась на то что нету такой директории — скорее всего у вас не установлены исходные тексты, как их установить есть в handbook
Копируем стандартный умолчательный конфиг GENERIC в файл, название которого позаимствует наше будущее ядро, у меня это BLACKRNL

root@srv1:/usr/src/sys/amd64/conf# cp GENERIC BLACKRNL

в файле BLACKRNL правим строчку где ident меняем GENERIC на BLACKRNL и в конец файла добавляем такие опции для включения поддержки IPSec в ядро

### IPSec Support ###
options         IPSEC
options         IPSEC_DEBUG
device          crypto

Остальное включаем/выключаем по желанию 🙂 Я у себя поодключал еще поддержку всякой ненужной ерунды, типа wi-fi, всяких непонятных сетевух и прочего барахла которого у меня никогда небыли и врятли когдато будет.
Выходим в директорию /usr/src и запускаем сборку ядра

root@srv1:/usr/src/sys/amd64/conf# cd /usr/src/
root@black:/usr/src# make buildkernel KERNCONF=BLACKRNL

после сборки устанавливаем ядро командой

root@srv1:/usr/src# make install kernel KERNCONF=BLACKRNL

После установки нового ядра нужна перезагрузка, но я рекомендую сразу настроить автонастройку после ребута нужных нам сетевых плюшек для тунеля
открываем файлик /etc/rc.conf и добавляем следующие строчки в конец

# <= IPSec tunnel => #
gif_interfaces="gif0"
gifconfig_gif0="177.111.22.33 100.200.100.200"
ifconfig_gif0="inet 10.0.12.1 10.0.11.1 netmask 255.255.255.252"

На втором сервере тоже пересобираем ядро и рихтуем /etc/rc.conf только ип пеменять местами

# <= IPSec tunnel => #
gif_interfaces="gif0"
gifconfig_gif0="100.200.100.200 177.111.22.33"
ifconfig_gif0="inet 10.0.11.1 10.0.12.1 netmask 255.255.255.252"

После этого перегружаем оба сервера

root@srv1:~# reboot

Поскольку у меня на обоих серверах включен pf и дефолтное правило для входящих пакетов block in all то надо было еще разрешить трафик одного шлюза на второй такими правилами
на srv1

pass in on $INET_IF from 100.200.100.200 keep state

на srv2

pass in on $INET_IF from 177.111.22.33 keep state

Дальше надо установить ipsec-tools. На обоих серверах я установил их из портов.

root@srv1:~# cd /usr/ports/security/ipsec-tools/
root@srv1:/usr/ports/security/ipsec-tools# make config

выбрал опции DEBUG, DPD, FRAG

root@srv1:/usr/ports/security/ipsec-tools# make configure
root@srv1:/usr/ports/security/ipsec-tools# make
root@srv1:/usr/ports/security/ipsec-tools# make install
root@srv1:/usr/ports/security/ipsec-tools# make clean
root@srv1:~# mkdir /usr/local/etc/racoon

создаем там файлик psk.txt в который пишем ip другой стороны туннеля и пароль (одинаковый на обоих шлюзах)

root@srv1:~# vim /usr/local/etc/racoon/psk.txt

И добавляем туда следующее

177.111.22.33 Set_Pass_Here

на втором серваке

100.200.100.200 Set_Pass_Here

Добавляем в /etc/rc.conf на обоих серверах

ipsec_enable="YES"
ipsec_program="/usr/local/sbin/setkey"
ipsec_file="/etc/ipsec.conf"
racoon_enable="YES"
racoon_flags="-l /var/log/racoon.log -f /usr/local/etc/racoon/racoon.conf"

Дальше правим файлик /etc/ipsec.conf
на сервере 1

root@srv1:~# cat /etc/ipsec.conf
spdadd 177.111.22.33/32 100.200.100.200/32 ipencap -P out ipsec esp/tunnel/177.111.22.33-100.200.100.200/require;
spdadd 100.200.100.200/32 177.111.22.33/32 ipencap -P in ipsec esp/tunnel/100.200.100.200-177.111.22.33/require;

на сервере 2

root@srv2:~# cat /etc/ipsec.conf
spdadd 100.200.100.200/32 177.111.22.33/32 ipencap -P out ipsec esp/tunnel/100.200.100.200-177.111.22.33/require;
spdadd 177.111.22.33/32 100.200.100.200/32 ipencap -P in ipsec esp/tunnel/177.111.22.33-100.200.100.200/require;

Настраиваем racoon
копируем конфиг из примеров

cp /usr/local/share/examples/ipsec-tools/racoon.conf.sample /usr/local/etc/racoon/racoon.conf

я привел данный конфиг к такому виду:
сервер 1

root@srv1:~# cat /usr/local/etc/racoon/racoon.conf
# $KAME: racoon.conf.sample,v 1.28 2002/10/18 14:33:28 itojun Exp $

# "path" affects "include" directives.  "path" must be specified before any
# "include" directive with relative file path.
# you can overwrite "path" directive afterwards, however, doing so may add
# more confusion.
#path include "/usr/local/v6/etc" ;
path include "/usr/local/etc/racoon" ;
#include "remote.conf" ;

# the file should contain key ID/key pairs, for pre-shared key authentication.
path pre_shared_key "/usr/local/etc/racoon/psk.txt" ;

# racoon will look for certificate file in the directory,
# if the certificate/certificate request payload is received.
#path certificate "/usr/local/openssl/certs" ;

# "log" specifies logging level.  It is followed by either "notify", "debug"
# or "debug2".
#log debug;
listen
{
       isakmp  177.111.22.33 [500];
}

remote 100.200.100.200 [500]
{
        exchange_mode aggressive,main;
        doi ipsec_doi;
        situation identity_only;
        my_identifier address 177.111.22.33;
        peers_identifier address 100.200.100.200;
        lifetime time 8 hour;
        passive off;
        generate_policy off;
        proposal_check obey;   # obey, strict, or claim
        proposal {
          encryption_algorithm    blowfish;
          hash_algorithm          md5;
          authentication_method   pre_shared_key;
          lifetime time           30sec;
          dh_group                2;
        }
}

remote anonymous
{
        #exchange_mode main,aggressive,base;
        exchange_mode main,base;

        #my_identifier fqdn "server.kame.net";
        #certificate_type x509 "foo@kame.net.cert" "foo@kame.net.priv" ;

        lifetime time 24 hour ; # sec,min,hour

        #initial_contact off ;
        #passive on ;

        # phase 1 proposal (for ISAKMP SA)
        proposal {
                encryption_algorithm 3des;
                hash_algorithm sha1;
                authentication_method pre_shared_key ;
                dh_group 2 ;
        }

        # the configuration could makes racoon (as a responder)
        # to obey the initiator's lifetime and PFS group proposal,
        # by setting proposal_check to obey.
        # this would makes testing "so much easier", but is really
        # *not* secure !!!
        proposal_check strict;
}

# phase 2 proposal (for IPsec SA).
# actual phase 2 proposal will obey the following items:
# - kernel IPsec policy configuration (like "esp/transport//use)
# - permutation of the crypto/hash/compression algorithms presented below
sainfo anonymous
{
        pfs_group 2;
        lifetime time 12 hour ;
        encryption_algorithm 3des, cast128, blowfish 448, des, rijndael ;
        authentication_algorithm hmac_sha1, hmac_md5 ;
        compression_algorithm deflate ;
}
root@srv1:~#

сервер 2

root@srv2:~# cat /usr/local/etc/racoon/racoon.conf
# $KAME: racoon.conf.sample,v 1.28 2002/10/18 14:33:28 itojun Exp $

# "path" affects "include" directives.  "path" must be specified before any
# "include" directive with relative file path.
# you can overwrite "path" directive afterwards, however, doing so may add
# more confusion.
#path include "/usr/local/v6/etc" ;
path include "/usr/local/etc/racoon" ;
#include "remote.conf" ;

# the file should contain key ID/key pairs, for pre-shared key authentication.
path pre_shared_key "/usr/local/etc/racoon/psk.txt" ;

# racoon will look for certificate file in the directory,
# if the certificate/certificate request payload is received.
#path certificate "/usr/local/openssl/certs" ;

# "log" specifies logging level.  It is followed by either "notify", "debug"
# or "debug2".
#log debug;

listen
{
       isakmp  100.200.100.200 [500];
}

remote 177.111.22.33 [500]
{
        exchange_mode aggressive,main;
        doi ipsec_doi;
        situation identity_only;
        my_identifier address 100.200.100.200;
        peers_identifier address 177.111.22.33;
        lifetime time 8 hour;
        passive off;
        generate_policy off;
        proposal_check obey;   # obey, strict, or claim
        proposal {
          encryption_algorithm    blowfish;
          hash_algorithm          md5;
          authentication_method   pre_shared_key;
          lifetime time           30sec;
          dh_group                2;
        }
}

remote anonymous
{
        #exchange_mode main,aggressive,base;
        exchange_mode main,base;

        #my_identifier fqdn "server.kame.net";
        #certificate_type x509 "foo@kame.net.cert" "foo@kame.net.priv" ;

        lifetime time 24 hour ; # sec,min,hour

        #initial_contact off ;
        #passive on ;

        # phase 1 proposal (for ISAKMP SA)
        proposal {
                encryption_algorithm 3des;
                hash_algorithm sha1;
                authentication_method pre_shared_key ;
                dh_group 2 ;
        }

        # the configuration could makes racoon (as a responder)
        # to obey the initiator's lifetime and PFS group proposal,
        # by setting proposal_check to obey.
        # this would makes testing "so much easier", but is really
        # *not* secure !!!
        proposal_check strict;
}

# phase 2 proposal (for IPsec SA).
# actual phase 2 proposal will obey the following items:
# - kernel IPsec policy configuration (like "esp/transport//use)
# - permutation of the crypto/hash/compression algorithms presented below
sainfo anonymous
{
        pfs_group 2;
        lifetime time 12 hour ;
        encryption_algorithm 3des, cast128, blowfish 448, des, rijndael ;
        authentication_algorithm hmac_sha1, hmac_md5 ;
        compression_algorithm deflate ;
}
root@srv2:~#

Перед запуском ракуна нужно еще разрешить передачу зашифрованного трафика через firewall
Для этого в /etc/pf.conf я добавил следующие строчки

# <= IPSec tunnel => #
pass in on $INET_IF from 100.200.100.200 keep state
pass on gif0 from any to any keep state
pass in quick proto esp from any to any
pass in quick proto ah from any to any
pass in quick proto ipencap from any to any
pass in quick proto udp from any port = 500 to any port = 500
pass in quick on gif0 from any to any
pass out quick proto esp from any to any
pass out quick proto ah from any to any
pass out quick proto ipencap from any to any
pass out quick proto udp from any port = 500 to any port = 500
pass out quick on gif0 from any to any

Лучше конечно заменить часть где from any to any на конкретные ip адреса серверов, обезопасив себя от возможности подключения третьей стороны.
после этого на обоих серверах запускаем ipsec

root@srv1:~# /etc/rc.d/ipsec start

после него запускаем racoon

root@srv1:~# /usr/local/etc/rc.d/racoon start

после этого у меня передача данных по туннелю пошла в зашифрованном виде, в этом можно убедиться подампив на внешнем интерфейсе одного из серверов трафик со второго.

root@srv1:~# tcpdump -n -e -ttt -i fxp0 host 100.200.100.200
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on fxp0, link-type EN10MB (Ethernet), capture size 96 bytes
00:00:00.000000 00:21:d8:68:61:7f > 00:02:b3:2e:26:71, ethertype IPv4 (0x0800), length 174: 100.200.100.200 > 177.111.22.33: ESP(spi=0x05c37c20,seq=0x19b), length 140
00:00:00.000173 00:02:b3:2e:26:71 > 00:21:d8:68:61:7f, ethertype IPv4 (0x0800), length 174: 177.111.22.33 > 100.200.100.200: ESP(spi=0x0e18d5d6,seq=0x199), length 140
00:00:01.009768 00:21:d8:68:61:7f > 00:02:b3:2e:26:71, ethertype IPv4 (0x0800), length 174: 100.200.100.200 > 177.111.22.33: ESP(spi=0x05c37c20,seq=0x19c), length 140
00:00:00.000181 00:02:b3:2e:26:71 > 00:21:d8:68:61:7f, ethertype IPv4 (0x0800), length 174: 177.111.22.33 > 100.200.100.200: ESP(spi=0x0e18d5d6,seq=0x19a), length 140
00:00:01.009800 00:21:d8:68:61:7f > 00:02:b3:2e:26:71, ethertype IPv4 (0x0800), length 174: 100.200.100.200 > 177.111.22.33: ESP(spi=0x05c37c20,seq=0x19d), length 140
00:00:00.000167 00:02:b3:2e:26:71 > 00:21:d8:68:61:7f, ethertype IPv4 (0x0800), length 174: 177.111.22.33 > 100.200.100.200: ESP(spi=0x0e18d5d6,seq=0x19b), length 140
00:00:01.009861 00:21:d8:68:61:7f > 00:02:b3:2e:26:71, ethertype IPv4 (0x0800), length 174: 100.200.100.200 > 177.111.22.33: ESP(spi=0x05c37c20,seq=0x19e), length 140
00:00:00.000173 00:02:b3:2e:26:71 > 00:21:d8:68:61:7f, ethertype IPv4 (0x0800), length 174: 177.111.22.33 > 100.200.100.200: ESP(spi=0x0e18d5d6,seq=0x19c), length 140
00:00:01.009778 00:21:d8:68:61:7f > 00:02:b3:2e:26:71, ethertype IPv4 (0x0800), length 174: 100.200.100.200 > 177.111.22.33: ESP(spi=0x05c37c20,seq=0x19f), length 140
00:00:00.000177 00:02:b3:2e:26:71 > 00:21:d8:68:61:7f, ethertype IPv4 (0x0800), length 174: 177.111.22.33 > 100.200.100.200: ESP(spi=0x0e18d5d6,seq=0x19d), length 140
^C
10 packets captured
111 packets received by filter
0 packets dropped by kernel
root@srv1:~#

Ну вот и забегал трафик в шифрованном виде по нашему VPN. Задача решена 🙂

  1. Комментов пока нет

  1. Январь 22nd, 2013

Why ask?