본문 바로가기

네트워크

transport_mode="tcp"는 조용히 무시된다 — 우연히 동작했던 프로파일의 정체 (Part 6)

같은 증상으로 검색해 오신 분들께

증상: 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에서 세션 정보를 보는 것이다.

 
bash
diagnose vpn ike gateway list

출력에서 봐야 할 줄:

 
name: ra-ipsec_0
...
transport: UDP          ← 구버전 프로파일로 접속 시
 
name: ra-ipsec_0
...
transport: TCP          ← 신버전 프로파일로 접속 시

이 한 줄이 며칠간의 잘못된 방향을 끝냈다.

 

4. 근본 원인 — 자료형

XML을 다시 봤다. 구버전에는 이렇게 들어 있었다.

 
xml
<!-- 구버전: 내가 손으로 쓴 값 -->
<transport_mode>tcp</transport_mode>

신버전에는 이렇게.

 
xml
<!-- 신버전: 내보낸 파일 기준으로 편집 -->
<transport_mode>1</transport_mode>

transport_mode는 열거형 정수다.

값의미
0 UDP
1 TCP
2 Auto (UDP 실패 시 TCP 폴백)

"tcp"는 유효한 값이 아니다. 그런데 파서가 오류를 내지 않는다. 파싱에 실패하면 기본값인 0(UDP)으로 떨어진다. 로그에 경고도 없다.

이게 Part 4에서 "내보내서 편집하라"고 쓴 이유다. 내가 초기에 XML을 손으로 쓰면서 사람이 읽기 좋은 값을 넣었고, 그게 조용히 무시됐다.

왜 이게 특히 나쁜 종류의 버그인가

세 가지가 겹친다.

  1. 오류가 없다. 잘못된 값이 거부되지 않는다.
  2. 폴백 결과가 동작한다. UDP로 잘 붙으니 문제로 인식되지 않는다.
  3. 설정 파일이 거짓을 말한다. 파일을 열어보면 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만 의미가 있다.

 
bash
# 7.4에서 확인
config vpn ipsec phase1-interface
    edit "ra-ipsec"
        set transport ?

여기서 나오는 선택지를 신뢰하되, 선택지가 존재하는 것과 그 기능이 완결되어 있는 것은 다르다는 걸 이번에 배웠다.

관련해서 확인한 것: fallback-tcp-threshold

7.4에 fallback-tcp-threshold라는 값이 있다. 우리 설정에는 5가 들어 있었다.

 
bash
get vpn ipsec phase1-interface ra-ipsec | grep fallback

이 값을 낮게 두면 폴백 판단이 더 빨리(더 민감하게) 일어난다. 실험해보니 이 값 조정은 실패율의 양상을 바꾸긴 했지만 실패 자체를 없애지 못했다. 증상을 이동시킬 뿐이었다.

이 관찰이 Part 8의 중요한 단서가 됐다. 파라미터를 바꿔서 증상이 "이동"하면 그건 원인을 찾은 게 아니라 원인을 회피할 확률을 바꾼 것일 가능성이 높다.

6. 조치

적용한 것

 
xml
<!-- 기본 프로파일: UDP -->
<transport_mode>0</transport_mode>

<!-- 백업 프로파일: TCP -->
<transport_mode>1</transport_mode>

프로파일 두 벌을 명시적으로 분리했다. Auto에 의존하지 않는다.

적용하지 않은 것

  • transport_mode=2 (Auto): 7.4에서 동작하지 않음
  • 7.6으로의 업그레이드: 다른 회귀 이슈가 있어 보류. Part 12에서 다룬다.

검증 절차에 추가한 것

프로파일을 배포하기 전에 반드시 실제 transport를 확인한다.

 
bash
# 접속 후 FortiGate에서
diagnose vpn ike gateway list | grep -E 'name:|transport:'

설정 파일을 읽는 것으로 검증을 대체하지 않는다. 이게 이 편의 결론이다.

7. 여기서 배운 것

  • 설정 파일에 써 있는 값과 실제 적용된 값은 다를 수 있다. 특히 파서가 관대할 때. 항상 런타임에서 확인한다.
  • 오류 없이 기본값으로 폴백하는 설계는 **"동작하는 잘못된 설정"**을 만든다. 이건 명시적 실패보다 훨씬 위험하다. 잘 돌아가는 동안 잘못된 사실을 학습하기 때문이다.
  • diff로 두 설정을 비교하기 전에, 두 설정이 실제로 다르게 동작하는지 런타임에서 확인한다. 나는 존재하지 않는 차이를 며칠 찾았다.
  • 문서화되지 않은 설정값은 자료형부터 의심한다. 열거형이 정수인지 문자열인지는 추측할 수 없다.
  • 파라미터를 바꿔서 증상이 사라지지 않고 "이동"하면, 원인을 못 찾은 것이다. 이 감각이 Part 8을 풀었다.

8. 그래서 원래 문제는

이 편에서 알아낸 건 "왜 두 프로파일이 다르게 동작했는가"였다. 원래 문제는 아직 그대로였다.

TCP transport로 붙으면 절반이 실패한다.

그리고 이제는 그게 진짜 문제라는 걸 알게 됐다. 구버전 프로파일이 안정적이었던 건 TCP를 안 썼기 때문이므로, 비교 대상이 사라졌다.

Part 7에서 잠깐 다른 문제를 다루고(그룹별 접근제어), Part 8에서 이 문제로 돌아온다.

반응형