OpenVPN의 UDP 응답이 잘못된 주소에서 나가는 이유
로컬 주소가 여러 개인 UDP 서버는 클라이언트가 접속한 주소와 다른 주소에서 응답할 수 있습니다. multihome 은 지원되는 플랫폼에서 출발지를 바로잡습니다.
OpenVPN 클라이언트가 한 주소로 접속하는데 서버가 다른 주소에서 응답하므로 터널이 끝내 올라오지 않습니다. 서버 로그에는 패킷 도착이 남고 캡처에는 응답이 나가는 모습이 찍히므로, 장애는 클라이언트 탓으로 돌아갑니다. 인터페이스가 여러 개인 호스트나 한 인터페이스에 주소가 여러 개인 호스트에서는 어느 주소가 쓰이는지에 대해 양쪽이 그저 의견이 다를 뿐입니다. 응답은 IP 계층에서 유효하지만, 많은 클라이언트는 접속한 주소가 아닌 곳을 출발지로 하는 데이터그램을 버립니다.
출발지가 바뀔 때 클라이언트가 보는 것
특정 로컬 주소에 묶이지 않은 UDP 소켓에는 고정된 출발지가 없으므로 커널이 전송 시점에 하나를 고릅니다. 그 선택은 클라이언트 주소 방향의 경로 조회에서 나오고, 출발지는 조회가 고른 인터페이스의 주소가 됩니다. 인터페이스가 하나인 머신에서는 선택이 보이지 않지만, 관리 주소와 공용 주소, 같은 네트워크 카드의 보조 주소가 있는 호스트에서는 라우팅 메트릭과 정책에 달려 있습니다. 정책 기반 라우팅은 규칙이 클라이언트가 도달한 적 없는 상위 링크를 고를 수 있어 불일치를 줄이기는커녕 늘립니다. 한 통신사에서 배운 기본 경로와 다른 쪽을 가리키는 출발지 규칙만 있으면 그것이 생깁니다.
응답을 필터링하는 클라이언트와 정확한 네 항목 조합과 출발지를 기대하는 연결 추적은 유용한 메시지도 없이 응답을 버립니다. 그러면 터널은 아무것도 도착하지 않은 것처럼 시간 초과되고, 그래서 이것이 클라이언트 측 방화벽 문제로 오해됩니다. 서버에서만 뜬 캡처는 응답이 실제로 나가기 때문에 원인을 설명하기는커녕 오류를 확인해 줄 뿐입니다. 다른 무엇을 바꾸기 전에 응답의 출발지와 클라이언트가 접속한 주소를 비교하십시오.
multihome 옵션이 실제로 하는 일
이 지시문은 구성 파일에서 multihome, 명령줄에서 --multihome 로 쓰이며, UDP 서버가 클라이언트 패킷이 도달한 주소에서 응답하도록 만듭니다. 커널은 수신 시 원래 목적지 주소를 보조 데이터로 넘기고, OpenVPN은 그 값을 응답의 출발지로 사용합니다. 그래서 와일드카드 주소에서 수신하는 서버는 IPv4 의 경우 local 0.0.0.0, IPv6 의 경우 그에 해당하는 값을 써서 각 클라이언트가 전용 리스너에 도달한 것처럼 동작합니다. 공용 주소로 들어온 클라이언트는 공용 주소에서 응답을 받고, 내부 주소의 클라이언트는 그 주소에서 받습니다. 패킷 경로에서 다른 것은 움직이지 않고, 경로와 필터 규칙, 터널 구성은 있던 그대로 남습니다.
이 마지막 성질 덕분에 옵션은 다른 면에서 정상 동작하는 서버에 안전하게 추가할 수 있고, 동시에 한 주소만 허용하는 필터는 고칠 수 없는 이유이기도 합니다. 패킷은 여전히 지나가는 경로에서 받아들여져야 하므로, 출발지 보정은 응답의 출처만 바꿀 뿐입니다. UDP 전용이기도 하며, TCP 리스너는 연결이 응답의 출발지 주소가 아니라 네 항목 조합으로 식별되므로 같은 형태로 이 문제를 겪지 않습니다.
고정 로컬 주소가 잘못된 기본값일 때
묶인 리스너는 항상 그 주소에서 응답하므로, 옵션을 꺼내 들기 전에 서버가 특정 로컬 주소에 묶여 있는지 확인하십시오. 인터페이스가 하나인 배포에서는 옳고, 클라이언트가 정당하게 둘 이상의 주소를 쓰기 시작하면 틀립니다. 묶음이 의도된 것이었다면 서버가 추가 주소에서 트래픽을 받아들여야 하는지 결정하십시오. 묶음을 없애면 노출이 커지므로, 허용되는 인터페이스와 출발지 네트워크는 묶인 주소만이 아니라 서비스와 필터가 강제해야 합니다.
OpenVPN 참조 문서는 이 옵션을 UDP 서버로 한정하고, 패킷 경로에서의 추가 처리에 주목하며, 어느 플랫폼이 지원하는지 기록합니다. 이를 전제로 계획하기 전에 설치된 릴리스에서 확인하십시오. 지원되지 않는 곳에서는 특정 주소를 묶거나 반환 경로를 고치는 것이 대안이며, 둘 다 언뜻 보이는 것보다 좁은 변경입니다. 와일드카드 수신에는 응답 너머의 영향도 있는데, 모든 주소에서 수신하는 서버는 호스트가 연결된 모든 네트워크에서 도달할 수 있으며, 그것은 누구도 의도하지 않은 노출일 수 있습니다.
응답의 출발지를 외부에서 증명하기
서버 바깥에서 시험하고, 무엇이든 캡처하기 전에 클라이언트가 쓴 정확한 주소와 전송 방식을 기록하십시오. 아래 세 가지 점검은 서로 다른 세 질문에 답하며, 순서가 중요합니다.
tcpdump -ni any udp port 1194
ss -lunp 'sport = :1194'
ip route get 203.0.113.10 from 198.51.100.20
캡처는 응답의 출발지 주소를 보여 주며, 글 전체가 이 사실에 달려 있습니다. 소켓 목록은 와일드카드 리스너와 특정 리스너가 구성 파일에서는 똑같이 보이지만 네트워크에서는 다르게 동작하기 때문에, 서버가 실제로 무엇을 묶었는지 보여 줍니다. 경로 조회는 커널이 그 흐름에 고를 출발지를 보여 주며, 무엇을 바꾸기 전에 캡처를 설명해 줍니다. IPv4 와 IPv6 는 별개의 리스너이고 별개의 조회이므로 셋 모두 따로 반복해야 하며, 한 계열에 대한 와일드카드 항목은 다른 계열에 대해 아무것도 말해 주지 않습니다.
라우팅과 검색, 필터링은 분리된 채로 남습니다
응답의 출발지를 보존하는 것은 나가는 경로를 설치하지 않고, 동적 DNS 를 갱신하지 않으며, 한 주소 계열이 다른 계열을 받아들이게 만들지도 않습니다. 상위 링크가 여러 개인 서버에서는 각 출발지의 반환 경로를 의도적으로 합의해야 하며, 그렇지 않으면 응답이 클라이언트 필터가 결코 허용하지 않은 인터페이스로 나갑니다. 마찬가지로, 프리픽스가 바뀐 뒤의 새 주소는 옛 레코드가 아니라 검색과 지원되는 재연결 흐름을 통해 클라이언트에 도달해야 합니다.
서버 ID 확인과 인증서 검증은 주소가 바뀌었다고 해서 검증되지 않은 상대를 받아들일 근거가 되지는 않으므로 그대로 두십시오. 응답이 이제 의도한 출발지에서 나가는데도 터널이 실패한다면 출발지 문제는 해결된 것으로 보고 넘어가십시오. 다음에 관찰되는 오류는 라우팅이나 필터링, 인증에 속하며, 리스너를 다시 바꾸어도 거기에 닿지 못합니다. 클라이언트가 접속한 주소 옆에 응답의 출발지를 티켓에 적어 두면, 다음 사람이 같은 사실을 명령 하나로 확인할 수 있습니다.