| 검색 | ?

Strongswan 분석

1.1. Overview

  • Strongswan은 IPsec 기반 VPN Solution으로 주로 Key를 관리하고 Linux Kernel과 Netlink로 교류한다.

    00-analysis-flow-v1-20161229-strongswan-overview.png
    [PNG image (217.92 KB)]


  • strongswan 빌드 예시 (Ubuntu 배포판 환경 기준)
    • 기본(최소) 의존성 패키지 설치 또는 직접 빌드하여 설치
      $ apt-get install -y \
          ca-certificates \
          ssl-cert \
          openssl \
          iproute2 \
          iputils-ping \
          libgmp10
      
    • strongSwan 빌드 및 설치 (수동 빌드 설치)
      $ VERSION="5.9.8" && \
        DEV_PACKAGES="wget bzip2 make gcc libssl-dev libgmp-dev" && \
        apt-get install -y $DEV_PACKAGES && \
        mkdir -p strongswan-build && \
        cd strongswan-build && \
        wget --no-check-certificate https://download.strongswan.org/strongswan-$VERSION.tar.bz2 && \
        tar -xjf strongswan-$VERSION.tar.bz2 && \
        cd strongswan-$VERSION && \
        ./configure --prefix=/usr --sysconfdir=/etc \
          --enable-charon --enable-ikev2 --enable-nonce --enable-random     \
          --enable-openssl --enable-pem --enable-x509 --enable-pubkey       \
          --enable-constraints --enable-pki --enable-socket-default         \
          --enable-kernel-netlink --enable-swanctl --enable-resolve         \
          --enable-eap-identity --enable-eap-md5 --enable-eap-mschapv2 --enable-eap-dynamic       \
          --enable-eap-tls --enable-updown --enable-vici                    \
          --enable-silent-rules  && \
         make -j4 all && make install && \
         ln -s /usr/libexec/ipsec/charon charon
      
    • 빌드 설치 확인
      $ ipsec version
      Linux strongSwan U5.9.8/K5.15.0-53-generic
      University of Applied Sciences Rapperswil, Switzerland
      
      => 이후 "/etc/strongswan.d/charon.conf" (기본 값 사용해도 무관), "/etc/ipsec.secrets" (IKE ID에 따른 Pre-shared key 등), "/etc/ipsec.conf" (SA1, SA2설정) 을 적절히 수정
      
      => 다음과 같은 명령으로 debug 실행할 수 있음.
      $ /usr/sbin/ipsec start --nofork --debug-all
      => 일반 데몬 실행은 다음과 같이 실행할 수 있음.
      $ /usr/sbin/ipsec start
      => 재시작 명령
      $ /usr/sbin/ipsec restart
      => 종료 명령
      $ /usr/sbin/ipsec stop
      

1.2. starter

  • starter 는 charon daemon을 실행 및 관리(재시작, 종료)해주는 기능 "ipsec.conf" 설정파일을 관리함
  • charon 을 실행관리하고 설정파일을 charon에 넘겨주는(stroke protocol) 역할

    01-analysis-flow-v1-20161229-strongswan-starter(launcher).png
    [PNG image (269.47 KB)]

1.3. charon

  • charon 는 starter에 의해서 실행되며 IKE key를 관리하는 strongswan daemon의 main 에 해당함.
  • 실제 각 동작부들(libcharon의 plugin)는 기능의 확장(추가)를 위한 addon부분과 Worker thread-pool를 사용한 작업처리부로 구현된 집합의 동작이라고 볼 수 있음.

    02-analysis-flow-v1-20161229-strongswan-charon(main).png
    [PNG image (267.74 KB)]

1.4. libcharon

  • charon에 의해서 구동되며 실제 libcharon/plugins/* 들을 초기화 및 Worker-thread-pool을 통해서 Multiple Core를 효율적으로 구동하도록 고안됨

    03-analysis-flow-v1-20161229-strongswan-libcharon.png
    [PNG image (195.26 KB)]


  • 내부 Worker thread의 갯수는 DEFAULT_THREADS 값을 통해서 사용함.
    • 기본값은 16이지만 최적은 CPU 갯수 * 2 로 맞추는게 좋음.
    • 통상적인 일반상황에서 최적의 Thread 갯수는 CPU갯수 및 Task/Job구현(비동기적 구현의 고려)에 따라 상이할 수 있음.
  • jobs 배열로 이루어진 linked list는 get_job() 함수에 의해서 각 Thread에 Conditional 접근을 통해서 Assign(할당)되고 Active(execute 활성) 됨.
  • job handler의 반환값에 따라서 다시 queue되거나 active 또는 1회 호출 후 종료되는등의 제어를 하게 됨. (위 flow 그림 참고)
  • 이러한 Worker thread(Thread-pool)와 Event (Timer, Multi-select, job, task등) 을 처리하는 방식에 대해서는 하기 링크의 libevent(libev) library 구현부에 대하여 먼저 보시면 도움이 될듯 합니다. (특히 chrome browser, node-js 에서 구현하는 방식) 결국 Multi-core 환경에서 가장 효율적으로 Core를 분배하여 사용하기 위한 하나의 개발에 대한 페러다임 방식이라고 할 수 있습니다. Proxy server등에서도 이러한 구조를 많이 도입합니다.
  • strongswan에서 그러면 fork에 의한 Process 와 pthread(POSIX Threads)에 의한 Thread 중에서 둘다 사용하는가?
    • 둘다 사용합니다. 다만 fork&execv에 의한 Process는 starter에서 charon daemon을 띄우기 위한 Launcher(process 감시기능)으로만 사용합니다.
    • 나머지 실제 모든 동작은 Thread pool (DEFAULT_THREADS 로 정의된 Thread 갯수만큼)을 job/task구조의 handler로 Assign하여 실행하는 구조라고 보시면 됩니다.

1.5. chunk 구조

  • libstrongswan 에는 pointer와 length 정보를 가진 binary 를 다루기 위한 구조를 다루기 위해서 chunk 구조를 가질 수 있습니다.
  • 암/복호화에는 수 많은 binary 들을 효율적으로 가르키고 얼마나 다루어야 하고 copy/merge/modify/wipe 등을 구행하는 작업이 많을 수 밖에 없습니다. 이것을 다루기 위한 함수 또는 매크로를 제공합니다. 이 때 할당된 chunk 인지 구분을 신중하게 확인하여야 메모리 누수를 막을 수 있습니다.

1.6. leak detective 방안 (메모리 누수 방지 방안)

  • strongswan 은 기본적으로 C언어기반의 객체지향 기법구현을 전반적으로 사용합니다. 때문에 객체생성과 소멸에 메모리 할당/해제를 많이 하게 됩니다.
    • 할당/해제 (malloc/free/...) 속도는 이러한 strongswan의 성능에 매우 큰 영향을 갖는다는 것도 인지할 필요가 있습니다. 때문에 성능 향상 도모를 위해서 jemalloc 같은 할당자로 대체해볼 수 있습니다.
  • 자칫 메모리 누수가 일어나기 쉬운 구조라고 볼 수 있는데 이것을 방어하고자 leak detective 방안이 고려되어 있습니다. (libstrongswan의 leak_detective 객체 구현 참고) 이를 잘 활용하면 꽤 대부분의 실수로 인한 누수를 찾을 수 있습니다. 물론 만능은 아니지만 이 구현을 잘 이용하면 메모리 누수를 예방할 수 있는 범위가 증가합니다.

1.7. printf_hook 구조

  • 일반적인 문자열 가공에 있어서 sprintf 계열 함수들은 C 언어에서 일반적으로 많이 사용합니다.
  • 하지만 객체를 문자열화하는데 있어서는 여러가지로 귀찮은 요소들이 있을 수 있는데 strongswan 은 hook 을 통한 구현으로 확장된 치환자들을 제공합니다.

1.8. stroke 통신 구조

  • strongswan은 크게 주요한것 구분으로 본다면 libstrongswan, libcharon, plugins, charon daemon, swanctl, starter, stroke command 등으로 나눌 수 있습니다.
    • stroke 통신제어부는 사용자가 별도의 통신으로 구현하여 교체할 수 있는 구조입니다. 전반적으로 libcharon을 어떻게 제어하는지 예제로써도 참고할 주요 분석 대상입니다.
  • 실제 핵심은 libcharon 과 libcharon-plugins 로 볼 수 있으며 기초부분은 libstrongswan 및 libstrongswan-plugins 들이 이를 받쳐줍니다.
  • charon daemon은 libcharon을 관장하는 main 함수라고 할 수 있습니다.
  • starter daemon은 charon daemon을 감시하고 실행해주는 launcher 역할과 설정파일을 읽어서 libcharon 의 stroke plugin 으로 이러한 설정 및 제어요소를 stroke protocol 로 전달하는 역할을 합니다.
  • stroke protocol은 매우 단순한 구조로써 요청과 응답을 구조를 가지고 있습니다.
  • 원한다면 starter를 내가 원하는 완전히 다른 설정 및 제어구조를 갖는 프로그램으로 교체하고 stroke 통신만 맞춰주면 새로운 설정 구조 및 제어구조를 가질 수도 있는 가능성을 제공합니다.
    • swanctl, stroke 명령어 구현을 참고할 수 있습니다.

1.9. task 구조

  • task 자료구조는 일종의 작업단위 문맥으로 나뉘어진 구현들의 job 들의 집합입니다.
  • libcharon 내의 task구현은 대부분 build_i, process_i, build_r, process_r method 를 구현하게 됩니다. 이는 다음과 같은 흐름에서의 구현집합을 의미합니다. 주로 message_t 자료구조를 통하여 패킷을 송/수신처리합니다.
      Initiator(행위의 시작)                         Responder(행위를 받는 입장)
      TASK->build_i
             =====================message===================>
                                                   TASK->process_r
                                                   TASK->build_r
             <====================message====================
      TASK->process_i
    
    • build_i : 요청할 작업을 준비하고 패킷을 만드는 과정들을 구현
    • process_r : 요청받은 패킷을 해석하고 이에 따르는 작업들을 준비하며 build_r 을 호출될 수 있는 Trigger 작업들 구현
    • build_r : 요청에 응답을 준비하고 응답패킷을 만드는 과정들을 구현
    • process_i : 응답받은 패킷을 해석하고 이에 따르는 작업들을 준비하고 완료 작업 또는 다음 단계를 Trigger 하는 작업들 구현


Copyright ⓒ MINZKN.COM
All Rights Reserved.