StrongSwan starter는 Charon 프로세스를 실행하고 구성 파일을 읽어 IKE/IPsec 연결 메세지를 charon 데몬으로 전달하는 역할을 한다.
- starter: strongswan/src/starter/
-
- 바이너리 위치: /usr/libexec/ipsec/starter
-
- charon: strongswan/src/charon/
Starter 실행 후 초기화 과정
Usage: starter [--nofork] [--auto-update <sec>]
[--debug|--debug-more|--debug-all|--nolog]
[--attach-gdb] [--daemon <name>]
[--conf <path to ipsec.conf>]
1. library_init()
- starter가 실행되면 가장 먼저 library_init()을 호출하여 기본 라이브러리를 초기화한다.
2. private_library_t 구조체 생성
- private_settings와 printf_hook_t를 초기화
3. 설정 파일 로드
- this->public.settings->load_files() 함수를 호출하여 설정 파일들을 로드한다.
- 설정 파일 경로로 this->public.conf를 사용하며, 일반적으로 이 경로는 /etc/strongswan.conf를 가리킨다.
#file strongswan.conf
charon {
load_modular = yes
plugins {
include strongswan.d/charon/*.conf
}
}
- load_modular = yes: charon이 모듈 방식으로 플러그인을 로드하도록 설정
- plugins: strongSwan에서 사용하는 플러그인들을 설정
- include strongswan.d/charon/*.conf: strongswan.d/charon/ 디렉토리에 있는 모든 .conf 파일을 포함
4. load_files 함수는 /etc/strongswan.conf 파일을 읽어들이고, strongswan.d 디렉토리 하위의 .conf 파일들을 로드한다.
- 여기에는 strongswan.conf, charon.conf, charon-logging.conf, pki.conf, pool.conf, scepclient.conf, starter.conf, swanctl.conf 등이 포함
- start.conf와 같은 추가 설정 파일도 필요에 따라 이 위치에서 로드
2. streams 생성
private_library_t *this;
this->public.streams = stream_manager_create();
- private_library_t 구조체의 streams 멤버를 초기화한다.
- stream_manager_create() 함수를 호출하여 스트림 관리자를 생성하고, 이를 this->public.streams에 할당한다.
Update configuration
1. command line argument parsing
--conf 옵션
- ipsec.conf 설정 파일 경로를 지정. 기본적으로 /etc/strongswan.d/starter.conf에서 config_file 항목을 참조하며, starter.conf 파일에 명시된 설정을 사용
2. ipsec.conf 파일 읽기 및 signal 처리 함수 설정
cfg = confread_load(config_file);
Start Charon daemon
1. starter_start_charon 호출하여 charon process 시작
2. starter_stroke_configure 호출하여 ipsec.conf 설정 넘겨줌
3. stroke_add_conn() 호출하여 connection 추가
- STR_ADD_CONN 메시지를 처리
- 메시지를 해석하고 this->config->add()를 호출하여 설정을 추가
void stroke_add_conn(stroke_socket_t *this, stroke_msg_t *msg)
{
// 메시지를 해석하고 IKE, peer 및 child 설정을 생성
ike_cfg_t *ike_cfg = build_ike_cfg(this, msg);
peer_cfg_t *peer_cfg = build_peer_cfg(this, ike_cfg);
child_cfg_t *child_cfg = build_child_cfg(this, msg);
// 설정 정보를 private_stroke_config_t 구조체의 리스트에 추가
this->config->add(this->config, ike_cfg, peer_cfg, child_cfg);
return send_stroke_msg(&msg);
}
- conf 데이터를 읽고 stroke를 통해 전송한다.
- charon 데몬에 전달할 구조체로 stroke_msg_t 구조체를 msg 변수로 선언하고 초기화
- msg.type을 STR_ADD_CONN으로 설정(새로운 연결을 추가하는 메시지)
- IKE 및 ESP 암호화 알고리즘, DPD 설정, 재키 설정, 터널 모드, MobIKE 지원 여부 등 추가
- left와 right의 endpoint 설정 (starter_stroke_add_end)
- 인증 방법(authby: leftauth or rightauth, rsa, psk, xauthrsasig..) 설정
- charon 데몬에 전달할 구조체로 stroke_msg_t 구조체를 msg 변수로 선언하고 초기화
4. add()
- this->config->add()는 stroke_config.c의 add() 함수
- 이 함수는 각종 설정 정보를 빌드하여 private_stroke_config_t의 리스트에 연결
void add(private_stroke_config_t *this, ike_cfg_t *ike_cfg, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg)
{
// 각 설정 정보를 빌드하고 리스트에 추가
this->ike_configs->insert_last(this->ike_configs, ike_cfg);
this->peer_configs->insert_last(this->peer_configs, peer_cfg);
this->child_configs->insert_last(this->child_configs, child_cfg);
}
5. send_stroke_msg(&msg) 함수에서 charon.ctl 소켓을 통해 charon 데몬으로 전송
#define CHARON_CTL_FILE IPSEC_PIDDIR "/charon.ctl"
ctl_addr.sun_family = AF_UNIX;
strcpy(ctl_addr.sun_path, CHARON_CTL_FILE);
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (connect(sock, (struct sockaddr *)&ctl_addr, offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0)
{
close(sock);
return -1;
}
/* send message */
if (write(sock, msg, msg->length) != msg->length)
{
close(sock);
return -1;
}
while ((byte_count = read(sock, buffer, sizeof(buffer)-1)) > 0)
{
buffer[byte_count] = '\0';
DBG1(DBG_APP, "%s", buffer);
}
- charon은 이 메시지를 받아 새로운 연결을 설정하고 IKE 세션을 관리한다.
6. STR_INITIATE 메시지 처리
- STR_INITIATE 메시지가 수신되면 stroke_initiate()가 호출되고, 이는 stroke_control.c의 initiate() 함수를 호출
- 이 함수는 설정 정보를 불러와 charon_initiate()를 호출하게된다.
void stroke_initiate(stroke_socket_t *this, stroke_msg_t *msg)
{
this->control->initiate(this->control, msg);
}
7. initiate()
- stroke_control.c의 initiate() 함수는 get_peer_cfg_by_name()을 사용해 peer_cfg를 가져오고, 해당 설정에서 child_cfg를 얻는다.
- 그 후, charon_initiate()가 호출된다.
void initiate(private_stroke_control_t *this, stroke_msg_t *msg)
{
peer_cfg_t *peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, msg->initiate.name);
child_cfg_t *child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
// 이후 charon_initiate() 호출
charon_initiate(charon, peer_cfg, child_cfg);
}
- 이후 charon_initiate()가 controller->initiate()를 호출하여 설정된 연결이 실제로 시작된다.
starter_stroke_add_conn <- connection 추가
starter_stroke_initiate_conn <- connection init
starter_stroke_route_conn <- connection route
References
'네트워크 보안 > 네트워크' 카테고리의 다른 글
XFRM (ipsec protocol framework) (0) | 2024.11.09 |
---|---|
strongswan #3 charon 초기화, plugin loading (0) | 2024.11.09 |
Netlink Sockets # How to use (0) | 2024.11.03 |
strongswan #1 IKEv2 소프트웨어 아키텍쳐, 메세지 포맷, config 설정 및 실행 방법 (0) | 2024.11.03 |
TCP/IP Stack 개발 #1 Ethernet & ARP (0) | 2024.08.04 |