OpenWRT StrongSwan IPSec VPN 설정

■ 시험 환경

- OpenBSD
WAN IP: 10.10.10.51
LAN IP : 192.168.10.254
LAN Network : 192.168.10.0/24
Test PC : 192.168.10.2

- OpenWRT Router
WAN IP : 10.10.10.250
LAN IP : 192.168.1.1
LAN Network : 192.168.1.0/24
Test PC : 192.168.1.2

■ OpenWRT Router 설정

▶ /etc/config/ipsec

# /etc/config/ipsec
config 'ipsec'
  option 'zone' 'vpn'
  list listen ''

config 'remote' 'acme'
  option 'enabled' '1'
  option 'gateway' '10.10.10.51'
  option 'authentication_method' 'psk'
  option 'pre_shared_key' '7d5813ab'
  list   'p1_proposal' 'pre_g2_aes_sha1'
  list   'tunnel' 'acme_lan'
  option 'local_identifier' 'ac2014@_utm'
  option 'remote_identifier' 'charon@_utm'

config 'p1_proposal' 'pre_g2_aes_sha1'
  option 'encryption_algorithm' 'aes256'
  option 'hash_algorithm' 'sha1'
  option 'dh_group' 'modp2048'

config 'tunnel' 'acme_lan'
  option 'local_subnet' '192.168.1.0/24'
  option 'remote_subnet' '192.168.10.0/24'
  option 'p2_proposal' 'g2_aes_sha1'

config 'p2_proposal' 'g2_aes_sha1'
  option 'encryption_algorithm' 'aes256'
  option 'authentication_algorithm' 'sha1'
  option 'pfs_group' 'modp2048'

------------------------------------------------------------------------------

▶ /etc/init.d/ipsec

#!/bin/sh /etc/rc.common
#/etc/init.d/ipsec - version 4

NAME=ipsec
START=60
STOP=60

. /lib/functions.sh

FileSecrets=/var/ipsec/ipsec.secrets
FileConn=/var/ipsec/ipsec.conf
FileCommon=/var/ipsec/strongswan.conf

FolderCerts=/var/ipsec/ipsec.d

ConfigUser()
{
  local enabled
  local xauth
  local name
  local password
  local crt_subject

  config_get_bool enabled $1 enabled 0
  [[ "$enabled" == "0" ]] && return

  config_get_bool xauth       $1 xauth       0
  config_get      name        $1 name        ""
  config_get      password    $1 password    ""

  if [ $xauth -eq 1 -a "$name" != "" -a "$password" != "" ]; then
    echo "$name : XAUTH \"$password\"" >> $FileSecrets
  fi
}

ConfigPhase1() {
  local encryption_algorithm
  local hash_algorithm
  local dh_group

  config_get encryption_algorithm  "$1" encryption_algorithm
  config_get hash_algorithm        "$1" hash_algorithm
  config_get dh_group              "$1" dh_group

  Phase1Proposal=${Phase1Proposal}","${encryption_algorithm}-${hash_algorithm}-${dh_group}
}

ConfigTunnel() {
  local local_subnet
  local local_nat
  local remote_subnet
  local p2_proposal
  local pfs_group
  local encryption_algorithm
  local authentication_algorithm

  config_get local_subnet             "$1"           local_subnet
  config_get local_nat                "$1"           local_nat ""
  config_get remote_subnet            "$1"           remote_subnet
  config_get p2_proposal              "$1"           p2_proposal
  config_get pfs_group                "$p2_proposal" pfs_group
  config_get encryption_algorithm     "$p2_proposal" encryption_algorithm
  config_get authentication_algorithm "$p2_proposal" authentication_algorithm

  [[ "$local_nat" != "" ]] && local_subnet=$local_nat

  p2_proposal="${encryption_algorithm}-${authentication_algorithm}-${pfs_group}"

  echo "conn $ConfigName-$1" >> $FileConn
  echo "  keyexchange=ike" >> $FileConn
  echo "  ikelifetime=24h" >> $FileConn
  echo "  keylife=23h" >> $FileConn
  echo "  rekeymargin=5m" >> $FileConn
  echo "  keyingtries=100" >> $FileConn
  echo "  mobike=no" >> $FileConn
  echo "  rekey=no" >> $FileConn
  echo "  reauth=no" >> $FileConn
  echo "  left=$LocalGateway" >> $FileConn
  echo "  right=$RemoteGateway" >> $FileConn
  echo "  leftsubnet=$local_subnet" >> $FileConn
  if [ "$AuthenticationMethod" = "psk" ]; then
    echo "  authby=secret" >> $FileConn
    echo "  rightsubnet=$remote_subnet" >> $FileConn
    echo "  auto=start" >> $FileConn
  elif [ "$AuthenticationMethod" = "xauth_psk_server" ]; then
    echo "  authby=xauthpsk" >> $FileConn
    echo "  xauth=server" >> $FileConn
    echo "  modeconfig=pull" >> $FileConn
    echo "  rightsourceip=$remote_subnet" >> $FileConn
    echo "  auto=add" >> $FileConn
  fi
  if [ "$LocalIdentifier" != "" ]; then
    echo "  leftid=$LocalIdentifier" >> $FileConn
  fi
  if [ "$RemoteIdentifier" != "" ]; then
    echo "  rightid=$RemoteIdentifier" >> $FileConn
  fi

  echo "  auth=esp" >> $FileConn
  echo "  esp=$p2_proposal" >> $FileConn
  echo "  ike=$Phase1Proposal" >> $FileConn
  echo "  type=tunnel" >> $FileConn
}

ConfigStrongSwan() {
  echo "threads = 16" > $FileCommon
  echo "replay_window = 32" >> $FileCommon
  echo "dos_protection = no" >> $FileCommon
  echo "block_threshold = 2000" >> $FileCommon
  echo "cookie_threshold = 2000" >> $FileCommon
  echo "init_limit_half_open = 2000" >> $FileCommon
  echo "retransmit_timeout = 60" >> $FileCommon
  echo "retransmit_tries = 30" >> $FileCommon
  echo "install_virtual_ip = no" >> $FileCommon
  echo "install_routes = no" >> $FileCommon
  echo "close_ike_on_child_failure = yes" >> $FileCommon
  echo "ikesa_table_size = 512" >> $FileCommon
  echo "ikesa_table_segments = 16" >> $FileCommon
  echo "reuse_ikesa = no" >> $FileCommon
}

ConfigRemote() {
  local enabled
  local gateway
  local pre_shared_key
  local authentication_method
  local local_identifier
  local remote_identifier

  ConfigName=$1

  config_get_bool enabled "$1" enabled 0
  [[ "$enabled" == "0" ]] && return

  config_get gateway               "$1" gateway
  config_get pre_shared_key        "$1" pre_shared_key
  config_get authentication_method "$1" authentication_method
  config_get local_identifier      "$1" local_identifier
  config_get remote_identifier     "$1" remote_identifier

  AuthenticationMethod=$authentication_method
  LocalIdentifier=$local_identifier
  RemoteIdentifier=$remote_identifier

  RemoteGateway=$gateway
  if [ "$RemoteGateway" = "any" ]; then
    RemoteGateway="%any"
    LocalGateway=`ip route get 1.1.1.1 | awk -F"src" '/src/{gsub(/ /,"");print $2}'`
  else
    LocalGateway=`ip route get $RemoteGateway | awk -F"src" '/src/{gsub(/ /,"");print $2}'`
  fi
  echo "$LocalGateway $RemoteGateway : PSK \"$pre_shared_key\"" >> $FileSecrets

  Phase1Proposal=""
  config_list_foreach "$1" p1_proposal ConfigPhase1
  Phase1Proposal=`echo $Phase1Proposal | cut -b 2-`

  config_list_foreach "$1" tunnel ConfigTunnel
}

PrepareEnvironment() {
  for d in cacerts aacerts ocspcerts crls acerts; do
    mkdir -p $FolderCerts/$d 2>/dev/null
  done

  if [ ! -L /etc/ipsec.d ]; then
    rm -rf /etc/ipsec.d 2>/dev/null
    ln -s $FolderCerts /etc/ipsec.d
  fi

  if [ ! -L /etc/ipsec.secrets ]; then
    rm /etc/ipsec.secrets 2>/dev/null
    ln -s $FileSecrets /etc/ipsec.secrets
  fi

  if [ ! -L /etc/strongswan.conf ]; then
    rm /etc/strongswan.conf 2>/dev/null
    ln -s $FileCommon /etc/strongswan.conf
  fi

  if [ ! -L /etc/ipsec.conf ]; then
    rm /etc/ipsec.conf 2>/dev/null
    ln -s $FileConn /etc/ipsec.conf
  fi


  echo "# generated by /etc/init.d/ipsec" > $FileConn
  echo "version 2" > $FileConn
  echo "config setup" >> $FileConn
  echo "  charondebug = \"ike 2,knl 2\"" >> $FileConn

  echo "# generated by /etc/init.d/ipsec" > $FileSecrets
}

CheckInstallation() {
  if [ ! -x /usr/sbin/ip ]; then
    echo /usr/sbin/ip missing
    echo install with \"opkg install ip\"
    exit
  fi

  for f in aes authenc cbc hmac md5 sha1; do
    if [ `opkg list kmod-crypto-$f | wc -l` -eq 0 ]; then
      echo kmod-crypto-$f missing
      echo install with  \"opkg install kmod-crypto-$f --nodeps\"
      exit
    fi
  done

  for f in aes gmp hmac kernel-netlink md5 random sha1 updown attr resolve; do
    if [ ! -f /usr/lib/ipsec/plugins/libstrongswan-${f}.so ]; then
      echo /usr/lib/ipsec/plugins/$f missing
      echo install with \"opkg install strongswan-mod-$f --nodeps\"
      exit
    fi
  done
}

start() {
  CheckInstallation
  PrepareEnvironment
  ConfigStrongSwan

  config_load users
  config_foreach ConfigUser user

  config_load ipsec
  config_foreach ConfigRemote remote

  /usr/sbin/ipsec start
}

stop() {
  /usr/sbin/ipsec stop
}

------------------------------------------------------------------------------

■ OpenBSD 설정

▶ /var/_utm/etc/ipsec.conf
#####################################################################
# Setup the IPSec IKE - 'test'
#####################################################################
ike dynamic esp tunnel from 192.168.10.0/24 to 192.168.1.0/24 local 10.10.10.51 peer 10.10.10.250 \
  main auth hmac-sha1 enc aes-256 group modp2048 lifetime 3600 \
  quick auth hmac-sha1 enc aes-256 group modp2048 lifetime 86400 \
  srcid 'charon@_utm' dstid 'ac2014@_utm' psk "7d5813ab" \
  tag 'IPSecIKE0001'



▶ 라우팅 테이블 추가

route add -inet 192.168.1.0/24 192.168.10.254

▶ VPN 연결 확인 (OpenWRT)

root@OpenWrt:/etc/config# ipsec statusall
Status of IKE charon daemon (strongSwan 5.0.0, Linux 3.3.8, mips):
  uptime: 3 minutes, since May 02 09:25:17 2014
  malloc: sbrk 118784, mmap 0, used 101856, free 16928
  worker threads: 6 of 16 idle, 9/1/0/0 working, job queue: 0/0/0/0, scheduled: 3
  loaded plugins: charon pkcs11 aes des sha1 sha2 md5 random nonce x509 revocation constraints pubkey pkcs1 pkcs8 pgp dnskey pem fips-prf gmp xcbc hmac attr kernel-netlink resolve socket-default stroke updown xauth-generic dhcp uci
Listening IP addresses:
  10.10.10.250
  192.168.1.1
Connections:
acme-acme_lan:  10.10.10.250...10.10.10.51  IKEv1
acme-acme_lan:   local:  [10.10.10.250] uses pre-shared key authentication
acme-acme_lan:   remote: [10.10.10.51] uses pre-shared key authentication
acme-acme_lan:   child:  192.168.1.0/24 === 192.168.10.0/24 TUNNEL
Security Associations (2 up, 0 connecting):
acme-acme_lan[2]: ESTABLISHED 101 seconds ago, 10.10.10.250[10.10.10.250]...10.10.10.51[10.10.10.51]
acme-acme_lan[2]: IKEv1 SPIs: 4eb6dc939cb992cc_i aca412bc4ed74980_r*, pre-shared key reauthentication in 2 hours
acme-acme_lan[2]: IKE proposal: AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048
acme-acme_lan{1}:  INSTALLED, TUNNEL, ESP SPIs: c9c25b9c_i 8b8a1502_o
acme-acme_lan{1}:  AES_CBC_256/HMAC_SHA1_96, 0 bytes_i, 0 bytes_o, rekeying in 43 minutes
acme-acme_lan{1}:   192.168.1.0/24 === 192.168.10.0/24
acme-acme_lan[1]: CONNECTING, 10.10.10.250[%any]...10.10.10.51[%any]
acme-acme_lan[1]: IKEv1 SPIs: f661063fe5d86514_i* 0000000000000000_r
acme-acme_lan[1]: Tasks queued: QUICK_MODE
acme-acme_lan[1]: Tasks active: ISAKMP_VENDOR ISAKMP_CERT_PRE MAIN_MODE ISAKMP_CERT_POST ISAKMP_NATD

▶ VPN 연결 확인 (OpenBSD)

# ipsecctl -vsa
FLOWS:
flow esp in from 192.168.1.0/24 to 192.168.10.0/24 peer 10.10.10.250 srcid charon@_utm dstid ac2014@_utm type use
flow esp out from 192.168.10.0/24 to 192.168.1.0/24 peer 10.10.10.250 srcid charon@_utm dstid ac2014@_utm type require

SAD:
esp tunnel from 10.10.10.250 to 10.10.10.51 spi 0x8419c640 auth hmac-sha1 enc aes-256
        sa: spi 0x8419c640 auth hmac-sha1 enc aes
                state mature replay 16 flags 0x4<tunnel>
        lifetime_cur: alloc 0 bytes 0 add 1399429397 first 0
        lifetime_hard: alloc 0 bytes 0 add 86400 first 0
        lifetime_soft: alloc 0 bytes 0 add 77760 first 0
        address_src: 10.10.10.250
        address_dst: 10.10.10.51
        identity_src: type ufqdn id 0: ac2014@_utm
        identity_dst: type ufqdn id 0: charon@_utm
        src_mask: 255.255.255.0
        dst_mask: 255.255.255.0
        protocol: proto 0 flags 0
        flow_type: type use direction in
        src_flow: 192.168.1.0
        dst_flow: 192.168.10.0
        tag: IPSecIKE0001
esp tunnel from 10.10.10.51 to 10.10.10.250 spi 0xc18b0b10 auth hmac-sha1 enc aes-256
        sa: spi 0xc18b0b10 auth hmac-sha1 enc aes
                state mature replay 16 flags 0x4<tunnel>
        lifetime_cur: alloc 0 bytes 18732 add 1399429397 first 1399429397
        lifetime_hard: alloc 0 bytes 0 add 86400 first 0
        lifetime_soft: alloc 0 bytes 0 add 77760 first 0
        address_src: 10.10.10.51
        address_dst: 10.10.10.250
        identity_src: type ufqdn id 0: charon@_utm
        identity_dst: type ufqdn id 0: ac2014@_utm
        src_mask: 255.255.255.0
        dst_mask: 255.255.255.0
        protocol: proto 0 flags 0
        flow_type: type use direction out
        src_flow: 192.168.10.0
        dst_flow: 192.168.1.0
        lifetime_lastuse: alloc 0 bytes 0 add 0 first 1399429621
        tag: IPSecIKE0001

위로 스크롤