Доступ к удаленным сетям с помощью IPSec GRE туннеля между Cisco IOS и FreeBSD

Опубликовано – 03.10.2019

Добрый день, уважаемые читатели. Хотел бы поделиться своим способом решения одной замысловатой задачи.

Допустим, имеется хост, по какой-либо причине недоступный на территории России. Доступ к этому хосту необходимо обеспечивать из небольшой локальной сети. Для решения проблемы есть возможность воспользоваться виртуальной машиной с FreeBSD 12, размещенной в облаке Microsoft Azure.

Конфигурация маршрутизатора Cisco:

!
crypto keyring MyTo
  pre-shared-key address YYY.YYY.YYY.YYY key MyMegaKey
!
crypto isakmp policy 10
 encr aes 256
 authentication pre-share
 group 2
!
crypto isakmp invalid-spi-recovery
crypto isakmp keepalive 120 20 periodic
crypto isakmp nat keepalive 20
crypto isakmp profile MyTo
   keyring MyTo
   match identity address YYY.YYY.YYY.YYY 255.255.255.255
   initiate mode aggressive
!
!
crypto ipsec transform-set MyNet esp-aes 256 esp-sha-hmac
!
crypto ipsec profile MyTo
 set transform-set MyNet
 set pfs group2
 set isakmp-profile MyTo
!
interface Tunnel10
 description --- To ---
 ip address 10.255.200.5 255.255.255.252
 ip mtu 1400
 ip tcp adjust-mss 1360
 tunnel source Vlan1
 tunnel mode ipsec ipv4
 tunnel destination YYY.YYY.YYY.YYY
 tunnel protection ipsec profile MyTo
!
!
router rip
 version 2
 redistribute static route-map RIP
 passive-interface default
 no passive-interface Vlan1
 network 10.0.0.0
 no auto-summary
!
ip forward-protocol nd
no ip http server
no ip http secure-server
ip flow-top-talkers
 top 20
 sort-by bytes
!
ip route 8.8.8.8 255.255.255.255 10.255.200.6
!
ip prefix-list RIP seq 100 permit 8.8.8.8/32

Так как туннель настраивается в уже существующем окружении, то нет возможности использовать crypto-map(это сильно облегчило бы задачу) и в качестве протокола динамической маршрутизации используется RIP. Я не стал поднимать на удаленном хосте quagga, а ограничился редистрибуцией маршрутов из статики на Cisco.

Приведу свои файлы конфигурации FreeBSD. Так как у нас туннель, а оба устройства имеют приватные адреса, то соответствующая запись в SPD определяются как 0.0.0.0/0, это приводит к тому, что ВЕСЬ трафик на стороне FreeBSD начинает заворачиваться в туннель. Для создания SPD приходится пользоваться racoon ( строка generate_policy on;), а ipsec.conf будет служить нам для формирования списка исключений хостов, трафик к которым НЕ БУДЕТ заворачиваться в туннель. В примере ниже, в туннель не будет завернут для адреса 8.8.8.8

[root@srv /usr/local/etc/racoon]# cat ipsec.conf
flush;
spdflush;

spdadd -4 10.229.33.4/32 8.8.8.8/32 any -P out none;
spdadd -4 8.8.8.8/32 10.229.33.4/32 any -P in none;
[root@srv /usr/local/etc/racoon]# cat racoon.conf
path pre_shared_key "/usr/local/etc/racoon/key.txt";
log notify;

padding {
        maximum_length 20;
        randomize off;
        strict_check off;
        exclusive_tail off;
}

listen {
        isakmp 10.229.33.4 [500];
        isakmp_natt 10.229.33.4 [4500];
}

remote XXX.XXX.XXX.XXX {
        exchange_mode aggressive,main;
        nat_traversal on;
        my_identifier address YYY.YYY.YYY.YYY;
        peers_identifier address 10.255.200.2;
        lifetime time 86400 sec;
        dpd_delay 20;
        dpd_retry 120;
        doi ipsec_doi;
        situation identity_only;
        passive off;
        proposal_check obey;
        generate_policy on;

        proposal {
                encryption_algorithm aes 256;
                authentication_method pre_shared_key;
                hash_algorithm sha1;
                dh_group 2;
        }
}

sainfo anonymous
{
        encryption_algorithm aes 256;
        authentication_algorithm hmac_sha1;
        pfs_group 2;
        compression_algorithm deflate;
}
[root@srv /usr/local/etc/racoon]# cat /etc/rc.conf
hostname="srv"
ifconfig_hn0="DHCP"
ifconfig_hn0_ipv6="inet6 accept_rtadv"
sshd_enable="YES"
# Set dumpdev to "AUTO" to enable crash dumps, "NO" to disable
dumpdev="AUTO"
waagent_enable="YES"

syslogd_enable="YES"
syslogd_flags="-ss"
cloned_interfaces="gre0"
ifconfig_gre0="10.255.200.6 10.255.200.5 netmask 255.255.255.255 link0 tunnel 10.229.33.4 XXX.XXX.XXX.XXX"

static_routes="remotelan"
route_remotelan="-net 10.255.0.0/16 10.255.200.5"
gateway_enable="YES"

# Enable PF
pf_enable="YES"
pflog_enable="YES"
pflog_logfile="/var/log/pf.log"
pflogd_enable="YES"
pfsync_enable="YES"

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

С такими настройками туннель устанавливается, только толку от него не много. Посмотрим на диагностику соединения:

[root@srv /usr/local/etc/racoon]# racoonctl show-sa isakmp
Destination            Cookies                           Created
XXX.XXX.XXX.XXX.60548     ca6587371be0d32e:5e1b0688d9b899e9 2019-09-26 14:10:08
[root@srv /usr/local/etc/racoon]# racoonctl show-sa ipsec
10.229.33.4[4500] XXX.XXX.XXX.XXX[60548]
        esp-udp mode=tunnel spi=3340752182(0xc71fd536) reqid=0(0x00000000)
        E: aes-cbc  1b1b434f 6307f876 ef9eab5e ddadaab6 fc1e7681 965bb341 8b00c751 2b6e0795
        A: hmac-sha1  370b608e c0c928c8 ac1058a9 10c59cc7 50cd5599
        seq=0x000009a3 replay=4 flags=0x00000000 state=mature
        created: Sep 26 14:10:09 2019   current: Sep 26 14:33:35 2019
        diff: 1406(s)   hard: 3600(s)   soft: 2880(s)
        last: Sep 26 14:10:11 2019      hard: 0(s)      soft: 0(s)
        current: 357656(bytes)  hard: 0(bytes)  soft: 0(bytes)
        allocated: 2467 hard: 0 soft: 0
        sadb_seq=1 pid=50504 refcnt=1
XXX.XXX.XXX.XXX[60548] 10.229.33.4[4500]
        esp-udp mode=tunnel spi=172050126(0x0a4146ce) reqid=0(0x00000000)
        E: aes-cbc  67f31bd3 60bc9040 103cd5d7 f6d30031 876921cc 0da3ca18 f2048c9e f9e620e5
        A: hmac-sha1  8455336c d0b1de88 bac3c433 88298de6 34c064c6
        seq=0x00000000 replay=4 flags=0x00000000 state=mature
        created: Sep 26 14:10:09 2019   current: Sep 26 14:33:35 2019
        diff: 1406(s)   hard: 3600(s)   soft: 2880(s)
        last: Sep 26 14:10:11 2019      hard: 0(s)      soft: 0(s)
        current: 162564(bytes)  hard: 0(bytes)  soft: 0(bytes)
        allocated: 2492 hard: 0 soft: 0
        sadb_seq=0 pid=50504 refcnt=1
[root@srv /usr/local/etc/racoon]# setkey -DP
8.8.8.8[any] 10.229.33.4[any] any
        in none
        spid=1740 seq=3 pid=50892 scope=global
        refcnt=1
0.0.0.0/0[any] 0.0.0.0/0[any] any
        in ipsec
        esp/tunnel/XXX.XXX.XXX.XXX-10.229.33.4/require
        created: Sep 26 14:10:09 2019  lastused: Sep 26 14:33:41 2019
        lifetime: 3600(s) validtime: 0(s)
        spid=1741 seq=2 pid=50892 scope=global
        refcnt=2
10.229.33.4[any] 8.8.8.8[any] any
        out none
        spid=1739 seq=1 pid=50892 scope=global
        refcnt=1
0.0.0.0/0[any] 0.0.0.0/0[any] any
        out ipsec
        esp/tunnel/10.229.33.4-XXX.XXX.XXX.XXX/require
        created: Sep 26 14:10:09 2019  lastused: Sep 26 14:33:41 2019
        lifetime: 3600(s) validtime: 0(s)
        spid=1742 seq=0 pid=50892 scope=global
        refcnt=3

Для того, чтобы мы могли достигать целевой хост, для чего всё и затевалось, через FreeBSD, нам необходимо настроить NAT и межсетевой экран:

######################################
# macros
######################################
# Define the external/public interface
ext_if="hn0"

# Define the internal LAN interface
int_if="gre0"

# Define a list of services to allow traffic for
tcp_services="{ 22 }"
udp_services="{ 500, 4500 }"

# Define what types of ICMP to allow
icmp_types="echoreq"

######################################
# options
######################################
set block-policy return
set loginterface $ext_if
set skip on lo
scrub in

######################################
# nat/rdr
######################################
# Handle the NAT forwarding for the LAN
nat on $ext_if inet from !($ext_if) -> ($ext_if:0)

######################################
# filter rules
######################################
# Block all incoming
block in

# Allow outgoing and keep state
pass out keep state

# The antispoof mechanism protects against activity from spoofed or forged IP addresses
antispoof quick for { lo $int_if }

# Allow requests for our ports/services defined in the $tcp_services macro above to the server
pass in on $ext_if inet proto tcp from any to ($ext_if) port $tcp_services
pass in on $ext_if inet proto udp from any to ($ext_if) port $udp_services
pass out on $ext_if inet proto tcp to any port $tcp_services keep state

# Allow the defined ICMP types
pass in inet proto icmp all icmp-type $icmp_types

# Allow all internal traffic
pass from ($int_if) to any keep state
pass quick on $int_if no state

В качестве теоретического упражнения (ни в коем случае не для решения практических задач обхода каких-либо то ни было блокировок!) был написан скрипт, который может брать неструктурированную базу IP адресов, например, базу адресов, заблокированных на территории РФ и генерировать два конфигурационных файла, ipsec.conf для FreeBSD и cisco.conf для Cisco примерно такого содержания:

...
spdadd -4 10.229.33.4/32 59.106.0.0/16 any -P out none;
spdadd -4 59.106.0.0/16 10.229.33.4/32 any -P in none; 
...
...
ip route 89.163.0.0 255.255.0.0 10.255.200.6
ip prefix-list RIP seq 4296 permit 89.163.0.0/16 
...

Обращаю ваше внимание, что на момент написания статьи в базе РКН было 1605333 адресов. Для того, чтобы не разорвало таблицу маршрутизации Cisco, в скрипте есть возможность суммаризации по маске, что дает 4518 сетей /16

Ссылка на скрипт https://github.com/MixaSg/tracery_stone

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*