같은 증상으로 검색해 오신 분들께
증상: FortiClient 프로파일에 TCP transport를 설정했는데 실제로는 UDP로 접속됨. 오류 메시지 없음. 또는 같은 설정이라고 생각한 두 프로파일의 동작이 다름. 환경: FortiClient 7.4.3 / FortiOS 7.4.11 결론: XML의 transport_mode는 숫자만 유효하다. 0=UDP, 1=TCP, 2=Auto. "tcp" 같은 문자열은 검증 오류 없이 무시되고 UDP 기본값으로 동작한다. 추가: 2(Auto)는 7.4에서 의미가 없다. UDP→TCP 폴백은 7.6 계열의 기능이다. 검색 키워드: FortiClient transport_mode IPsec over TCP not working wrong transport phase 1 uses non udp transport_mode xml
1. 증상 — 설명할 수 없는 두 프로파일
Part 5의 다섯 개 원인을 다 잡고 나서 남은 상황이었다.
프로파일이 두 벌 있었다. 하나는 초기 작업 중에 만든 것, 하나는 정리하면서 새로 만든 것. 내 인식으로는 transport 설정이 같았다. 그런데 동작이 달랐다.
| 구버전 (초기 작업분) | TCP | UDP | 안정 |
| 신버전 (정리한 것) | TCP | TCP | 절반 실패 |
당시 나는 이걸 이렇게 해석했다.
"구버전 프로파일에 뭔가 다른 설정이 더 있어서 TCP가 안정적으로 동작하는 것이다. 그 차이를 찾으면 된다."
완전히 거꾸로였다. 구버전은 TCP로 붙은 적이 없었다. UDP로 붙고 있었고, 그래서 안정적이었던 것이다.
2. 처음 세운 가설과, 그것이 왜 틀렸는가
첫 가설: 구버전 프로파일에 TCP 안정화에 기여하는 설정이 숨어 있다.
이 가설이 위험했던 이유는 그럴듯한 데다가 검증하기 쉬웠기 때문이다. 두 파일을 diff하면 되니까.
실제로 diff를 떴고, 차이가 몇 군데 나왔고, 그 차이들을 하나씩 신버전에 옮겨봤다. 당연히 효과가 없었다. 그러자 "아직 못 찾은 차이가 있다"고 결론 내리고 더 세밀하게 비교했다.
여기서 내가 하지 않은 질문이 있다.
"구버전이 정말 TCP로 붙고 있는가?"
이걸 확인하지 않았다. 프로파일에 그렇게 써 있으니 그런 줄 알았다. 설정 파일에 써 있는 것과 실제 동작을 검증 없이 동일시한 것이 이 편의 핵심 실수다.
3. 관측 — 실제로 무엇으로 붙고 있었나
확인 방법은 단순했다. FortiGate에서 세션 정보를 보는 것이다.
diagnose vpn ike gateway list
출력에서 봐야 할 줄:
name: ra-ipsec_0
...
transport: UDP ← 구버전 프로파일로 접속 시
name: ra-ipsec_0
...
transport: TCP ← 신버전 프로파일로 접속 시
이 한 줄이 며칠간의 잘못된 방향을 끝냈다.
4. 근본 원인 — 자료형
XML을 다시 봤다. 구버전에는 이렇게 들어 있었다.
<!-- 구버전: 내가 손으로 쓴 값 -->
<transport_mode>tcp</transport_mode>
신버전에는 이렇게.
<!-- 신버전: 내보낸 파일 기준으로 편집 -->
<transport_mode>1</transport_mode>
transport_mode는 열거형 정수다.
| 0 | UDP |
| 1 | TCP |
| 2 | Auto (UDP 실패 시 TCP 폴백) |
"tcp"는 유효한 값이 아니다. 그런데 파서가 오류를 내지 않는다. 파싱에 실패하면 기본값인 0(UDP)으로 떨어진다. 로그에 경고도 없다.
이게 Part 4에서 "내보내서 편집하라"고 쓴 이유다. 내가 초기에 XML을 손으로 쓰면서 사람이 읽기 좋은 값을 넣었고, 그게 조용히 무시됐다.
왜 이게 특히 나쁜 종류의 버그인가
세 가지가 겹친다.
- 오류가 없다. 잘못된 값이 거부되지 않는다.
- 폴백 결과가 동작한다. UDP로 잘 붙으니 문제로 인식되지 않는다.
- 설정 파일이 거짓을 말한다. 파일을 열어보면 tcp라고 써 있다.
즉 **"동작하는 잘못된 설정"**이다. 이게 몇 주 동안 잘 돌았고, 그 기간 동안 나는 "우리 환경에서 TCP는 안정적"이라는 잘못된 사실을 믿고 있었다.
5. 2(Auto)를 쓰려던 시도
원인을 알고 나서 자연스럽게 떠오른 생각.
transport_mode를 2로 두면 UDP를 먼저 시도하고 실패하면 TCP로 넘어간다. 프로파일 하나로 끝난다.
이것도 안 됐다. 이유를 찾는 데 또 시간이 걸렸다.
Auto transport(UDP 실패 시 TCP로 폴백하는 메커니즘)는 FortiOS 7.6 계열에서 도입된 기능이다. 7.4.x에서는 클라이언트가 2를 보내도 게이트웨이 쪽에 대응 동작이 없다.
FortiGate 쪽 Phase1의 transport 값도 7.4에서는 udp와 tcp만 의미가 있다.
# 7.4에서 확인
config vpn ipsec phase1-interface
edit "ra-ipsec"
set transport ?
여기서 나오는 선택지를 신뢰하되, 선택지가 존재하는 것과 그 기능이 완결되어 있는 것은 다르다는 걸 이번에 배웠다.
관련해서 확인한 것: fallback-tcp-threshold
7.4에 fallback-tcp-threshold라는 값이 있다. 우리 설정에는 5가 들어 있었다.
get vpn ipsec phase1-interface ra-ipsec | grep fallback
이 값을 낮게 두면 폴백 판단이 더 빨리(더 민감하게) 일어난다. 실험해보니 이 값 조정은 실패율의 양상을 바꾸긴 했지만 실패 자체를 없애지 못했다. 증상을 이동시킬 뿐이었다.
이 관찰이 Part 8의 중요한 단서가 됐다. 파라미터를 바꿔서 증상이 "이동"하면 그건 원인을 찾은 게 아니라 원인을 회피할 확률을 바꾼 것일 가능성이 높다.
6. 조치
적용한 것
<!-- 기본 프로파일: UDP -->
<transport_mode>0</transport_mode>
<!-- 백업 프로파일: TCP -->
<transport_mode>1</transport_mode>
프로파일 두 벌을 명시적으로 분리했다. Auto에 의존하지 않는다.
적용하지 않은 것
- transport_mode=2 (Auto): 7.4에서 동작하지 않음
- 7.6으로의 업그레이드: 다른 회귀 이슈가 있어 보류. Part 12에서 다룬다.
검증 절차에 추가한 것
프로파일을 배포하기 전에 반드시 실제 transport를 확인한다.
# 접속 후 FortiGate에서
diagnose vpn ike gateway list | grep -E 'name:|transport:'
설정 파일을 읽는 것으로 검증을 대체하지 않는다. 이게 이 편의 결론이다.
7. 여기서 배운 것
- 설정 파일에 써 있는 값과 실제 적용된 값은 다를 수 있다. 특히 파서가 관대할 때. 항상 런타임에서 확인한다.
- 오류 없이 기본값으로 폴백하는 설계는 **"동작하는 잘못된 설정"**을 만든다. 이건 명시적 실패보다 훨씬 위험하다. 잘 돌아가는 동안 잘못된 사실을 학습하기 때문이다.
- diff로 두 설정을 비교하기 전에, 두 설정이 실제로 다르게 동작하는지 런타임에서 확인한다. 나는 존재하지 않는 차이를 며칠 찾았다.
- 문서화되지 않은 설정값은 자료형부터 의심한다. 열거형이 정수인지 문자열인지는 추측할 수 없다.
- 파라미터를 바꿔서 증상이 사라지지 않고 "이동"하면, 원인을 못 찾은 것이다. 이 감각이 Part 8을 풀었다.
8. 그래서 원래 문제는
이 편에서 알아낸 건 "왜 두 프로파일이 다르게 동작했는가"였다. 원래 문제는 아직 그대로였다.
TCP transport로 붙으면 절반이 실패한다.
그리고 이제는 그게 진짜 문제라는 걸 알게 됐다. 구버전 프로파일이 안정적이었던 건 TCP를 안 썼기 때문이므로, 비교 대상이 사라졌다.
Part 7에서 잠깐 다른 문제를 다루고(그룹별 접근제어), Part 8에서 이 문제로 돌아온다.
'네트워크' 카테고리의 다른 글
| 다시 한다면 무엇을 바꿀까 — 그리고 아직 끝나지 않은 것들 (Part 12) (0) | 2026.07.25 |
|---|---|
| authusrgrp를 쓰면 방화벽 정책의 그룹 매칭이 죽는다 — 문서에 없던 상호작용 (Part 7) (0) | 2026.07.25 |
| IKE는 붙는데 인증이 안 된다 — 원인이 하나가 아니라 다섯 개였다 (Part 5) (0) | 2026.07.25 |
| EMS 없이 150명에게 FortiClient 프로파일 배포하기 (Part 4) (0) | 2026.07.25 |
| FortiGate Phase1/Phase2와 IP 풀 설계 — 나중에 살아남을 대역 나누기 (Part 3) (0) | 2026.07.25 |