VPN 게이트웨이의 MSS 클램핑: 무엇을 고치고 무엇을 고치지 않는가
클램핑은 TCP 핸드셰이크에서 MSS를 다시 써서 세그먼트가 터널에 맞게 합니다. UDP나 망가진 path-MTU 검사를 고치지는 않습니다. 순서대로 세 가지 검사.
작은 요청은 되는데 큰 다운로드가 멈추고, 누군가 MSS 클램핑을 제안한다. 그 제안은 올바른 순서로 시도할 가치가 있을 만큼 자주 맞고, 무작정 적용하면 반나절을 날릴 만큼 자주 틀린다. 아래 세 가지 검사가 진짜 TCP 크기 문제를 UDP 문제, 망가진 path-MTU 탐색, 그리고 재작성해야 할 핸드셰이크를 결코 보지 못하는 클램프로부터 구분한다.
실패의 형태부터 시작하라
크기 결함에는 서명이 있다. 연결이 맺어지고 인증과 작은 응답이 성공한 뒤, 전체 크기 세그먼트가 필요해지는 순간 전송이 무기한 멈춘다. 텍스트는 로드하지만 이미지를 끝내지 못하는 페이지도 더 작은 규모의 같은 결함이다. 아무것도 전혀 연결되지 않는다면 문제는 경로의 더 앞쪽에 있고 클램핑은 도움이 되지 않는다. 클램프는 결코 도착하지 않은 핸드셰이크를 고칠 수 없다.
이 서명이 존재하는 이유는 세그먼트 크기가 바로 핸드셰이크에서 합의되기 때문이다. 각 측은 최대 세그먼트 크기를 TCP 옵션으로 알리고, 송신자는 상대의 알림을 존중한다. 경로가 그렇게 큰 세그먼트를 나를 수 없다면, 실패는 나중에 송신자가 마침내 하나를 시도할 때 나타난다.
그 증상을 읽는 동안 전송 계층을 계속 보라. 클램핑은 TCP 옵션 재작성이므로 같은 터널 아래에서 멈추는 음성이나 영상 통화는 MSS 문제가 아니며 그것으로 나아지지 않는다. TCP 옵션을 건드리기 전에 전송 계층을 적어 두라.
경로의 비용을 매기고 터널과 비교하라
중요한 숫자는 두 개이며 자주 혼동된다. path-MTU는 경로가 단편화 없이 나르는 가장 큰 패킷이고, IPv4의 알림 MSS는 그 값에서 IP와 TCP 헤더 40바이트를 뺀 값, IPv6는 60을 뺀 값이다. 터널 캡슐화는 내부 패킷이 시작되기도 전에 예산의 일부를 소비한다.
ping -M do -s 1400 198.51.100.20
tracepath 198.51.100.20
do-not-fragment 비트를 준 ping은 그 페이로드 크기의 패킷이 살아남는지 알려 준다. 실패할 때까지 크기를 바꾸면 경로 한계를 경험적으로 찾은 것이다. tracepath 출력은 경로를 따라 발견된 MTU를 보고하는데, 잘 될 때는 더 빠르고 중간 홉이 프로브를 거를 때는 덜 신뢰할 만하다.
이제 터널 오버헤드를 빼라. 외부 IP 헤더, UDP 헤더, 터널 전용 헤더가 모두 같은 1500바이트에서 나오므로 일반적인 이더넷 기반에서 쓸 수 있는 내부 MTU는 물리 링크가 암시하는 것보다 낮다. 계산한 내부 MTU가 상대의 알림보다 낮다면 추측이 아니라 진짜 클램프 후보를 찾은 것이다. 계산값이 이미 상대의 알림보다 높다면 여기서 멈추고 다른 곳을 살펴라.
핸드셰이크가 지나가는 곳에 클램프를 두라
클램프는 게이트웨이를 지나는 SYN과 SYN-ACK 패킷의 MSS 옵션을 재작성하여 동작한다. 규칙이 어느 방향도 결코 지나지 않는 인터페이스에 있으면 협상은 그대로 끝나고 증상은 남는다. 그래서 값보다 배치가 결과를 더 많이 좌우한다.
| Symptom | What it points to | Next check |
|---|---|---|
| Handshake completes, large transfer stalls | Segment size larger than the path can carry | Path MTU against the tunnel's effective MTU |
| Nothing connects, small or large | Routing, firewall or keying failure | Not MSS; look at the tunnel state |
| Only UDP applications stall | Datagram size or a dropped ICMP error | Platform-specific UDP handling, not clamping |
| Fixed after reconnect, returns later | Clamp applied to one direction or one interface | Rule placement and the handshake path |
방향이 나머지 절반이다. 한 방향만 클램핑하면 흐름의 절반은 고쳐지고 나머지는 간헐적으로 보이는 방식으로 계속 실패하므로, 전달되는 트래픽의 양방향에 모두 적용하라. 터널 인터페이스에 대한 고전적인 Linux 형태는 SYN 패킷과 일치하는 mangle 규칙이다.
iptables -t mangle -A FORWARD -o tun0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
--clamp-mss-to-pmtu이 실제로 무엇을 하는지 보라. 경로의 MTU에서 값을 도출한다, 이것이 항상 터널의 실제 페이로드 예산은 아니다. 내부 경로와 외부 경로가 다른 경로 기반 터널에서는 이전 검사에서 계산한 명시적 값이 자동 값보다 예측 가능하다.
새 연결로 검증하고 피드백을 살려 두라
이미 맺어진 연결은 협상한 MSS를 유지하므로 같은 세션에서 테스트해도 아무것도 증명하지 못한다. 변경 후 새 연결을 열고 협상된 값을 직접 읽어라, 우연히 끝나는 전송에서 추론하지 말고.
ss -tin dst 198.51.100.20
iptables -t mangle -S | grep TCPMSS
첫 번째 명령은 소켓의 MSS를 혼잡 상태와 함께 보고하며, 클램프가 효과를 냈다는 가장 빠른 확인이다. 두 번째는 추가했다고 생각하는 규칙이 실제로 존재하는 규칙인지, 그것이 놓인 테이블에서 확인한다.
다음으로 고치지 않은 메커니즘을 보호하라. path-MTU 탐색은 ICMP fragmentation-needed 메시지가 송신자에게 도달하는 데 의존하므로, 그것을 버리는 방화벽은 올바른 클램프가 있어도 큰 전송을 계속 망가뜨린다. 터널 경로에 대해 그 메시지를 허용하거나, 클램핑이 당신이 선택한 정책을 보상하고 있음을 받아들여라.
마지막으로 클램프를 조정 손잡이로 다루려는 유혹을 물리쳐라. 세그먼트 크기를 제한하므로 전혀 필요 없던 경로에서 처리량을 희생한다. 세 검사 뒤에 적용하면 표적 수리이고, 먼저 적용하면 원래 결함을 숨기고 이후 모든 테스트에 두 번째 변수를 더하는 변경이다. 그 거래는 기본이 아니라 의도적으로 해야 한다.
측정한 path-MTU, 뺀 터널 오버헤드, 추가한 규칙, 그 뒤에 본 MSS를 적어 두라. 숫자 네 개면 다음 사고는 조사가 아니라 조회가 된다.