LAN 서버의 VPN 클라이언트: 응답이 엉뚱한 경로로 나가는 이유
VPN에 접속한 호스트는 기본 경로를 얻으므로 LAN 클라이언트로 가는 응답이 터널로 빠져나갑니다. 더 좁은 반환 경로를 추가하고 확인하세요.
증상은 한 가지 모양을 따릅니다. 호스트가 잘 동작하다가 클라이언트로서 VPN에 연결되면, LAN 클라이언트는 그 호스트에 닿는데 응답은 사라집니다. 호스트에서 캡처해 보면 응답이 LAN 인터페이스가 아니라 터널 장치로 나갑니다. 터널 자체는 고장이 아니고, 고칠 것은 경로이지 재연결이 아닙니다. 아래 네 가지 점검을 차례로 수행하고 처음 실패하는 지점에서 멈추세요.
응답은 새 패킷이지 경로의 역주행이 아닙니다
응답이 요청이 지나간 길을 그대로 되돌아온다는 생각을 버리는 편이 좋습니다. 라우팅은 보내는 호스트에서 패킷마다, 방향마다 결정됩니다. 터널 안에서 10.64.0.23 에서 온 요청은 반환 경로를 만들지 않습니다. 호스트가 응답할 때 그 응답은 새 패킷으로서 테이블과 대조되고 이기는 경로로 나갑니다.
LAN도 함께 서비스하는 머신에서 전체 터널 클라이언트를 쓰면 이렇게 혼란스러운 장애가 나오는 이유입니다. 클라이언트는 기본 경로를, 또는 일부 클라이언트가 선호하는 두 개의 반쪽 기본 경로를 설치하고, LAN 클라이언트로 가는 응답이 이제 터널과 일치합니다. 응답은 제공자로 향하고, 제공자에게는 그것을 전달할 이유가 없으며, 호스트는 살아 있고 로컬에서 응답하는데도 LAN 클라이언트는 시간 초과를 봅니다. 캡처가 그것을 분명히 보여 주고, 라우팅 테이블이 설명합니다.
나머지를 읽는 동안 두 서브넷을 염두에 두세요. 하나는 원격 클라이언트가 오는 VPN 주소 풀로, 이 예에서는 10.64.0.0/24 입니다. 다른 하나는 계속 동작해야 하는 LAN으로, 172.16.24.0/24 이고 라우터는 172.16.24.1 에 있습니다. 버그는 둘 사이의 트래픽을 기본 경로가 결정한다는 점입니다.
캡처와 조회로 증명하세요
무엇이든 바꾸기 전에 응답이 어느 장치를 쓸지 확인하세요. 조회는 캡처보다 빠르고, 패킷이 만들어질 때 커널이 답할 바로 그 질문에 답합니다.
ip route get 10.64.0.23 from 172.16.24.10
tcpdump -ni any -c 6 icmp
응답을 두 부분으로 읽으세요. dev tun0 을 가리키면 호스트가 응답을 캡슐화해 제공자에게 넘기고, LAN 클라이언트는 그것을 절대 보지 못합니다. dev eth0 을 가리키는데 클라이언트가 여전히 시간 초과라면 경로는 이미 옳고 패킷이 나중에 버려지는 것이며, 이는 다른 문제이고 해법도 다릅니다.
같은 단계의 캡처가 ping으로는 풀 수 없는 의문을 정리합니다. LAN 클라이언트에 에코 응답이 도착한다는 것은 어딘가의 경로가 동작한다는 증거이지 어느 인터페이스가 그것을 실어 날랐는지는 아닙니다. 그래서 캡처는 호스트 자체에서 수행하고 프레임이 어디로 나가는지 보세요. 같은 서브넷의 프린터는 계속 응답합니다. 직접 경로가 터널의 기본 경로보다 더 구체적이기 때문입니다. 포워딩된 포트도 다른 흐름과 똑같이 실패합니다. 인터페이스를 고르는 것은 테이블이고 연결이 아니기 때문입니다.
터널을 앞서는 가장 좁은 경로를 넣으세요
결정하는 것은 메트릭이 아니라 프리픽스 길이이므로, LAN 라우터를 거치는 클라이언트 풀 경로는 VPN 클라이언트가 넣는 어떤 기본 경로도 이깁니다. 메트릭 수술은 필요 없고, 기본 경로는 클라이언트가 둔 자리에 그대로 둘 수 있습니다.
ip route replace 10.64.0.0/24 via 172.16.24.1 dev eth0
ip route get 10.64.0.23 from 172.16.24.10
두 번째 add 대신 replace 를 쓰세요. 다시 연결한 클라이언트는 이미 자기 항목을 넣어 두었고, 두 번째 add 는 권한 문제처럼 읽히는 기존 경로 오류로 실패합니다. Windows 호스트에서 같은 역할은 route add 10.64.0.0 mask 255.255.255.0 172.16.24.1 -p 이고, -p 는 재부팅을 넘겨 항목을 유지합니다. 터널이 다시 올라올 때 클라이언트가 테이블을 다시 만들 수 있기 때문입니다. 현재 Windows 호스트에서 지원되는 같은 역할은 New-NetRoute -DestinationPrefix 10.64.0.0/24 -NextHop 172.16.24.1 -InterfaceAlias Ethernet -PolicyStore PersistentStore 이며, 오래된 route 명령은 레거시 형태로 남아 있습니다.
한 가지 세부가 이것이 옳은지 아니면 그럴듯한지만 결정합니다. 다음 홉은 클라이언트로 돌아가는 길을 실제로 가진 라우터여야 합니다. 터널로만 닿는 주소로 경로를 향하게 하면 깔끔한 실패가 아니라 간헐적 손실로 나타나는 루프가 생깁니다. 줄을 확정하기 전에 다음 홉이 LAN 서브넷에 있는지 확인하세요.
재연결 후에도 응답을 유지하세요
손으로 추가한 경로는 기껏해야 다음 재연결까지만 살아남습니다. 클라이언트 풀이 동적이라면 서버 구성에 고정해, 라우팅한 프리픽스가 클라이언트가 받는 프리픽스로 남게 하세요. 그렇지 않으면 항목이 빈 범위를 가리키고 증상은 몇 주 뒤 뚜렷한 원인 없이 돌아옵니다. 경로를 클라이언트 자체의 up 스크립트에 적는 것이 또 하나의 신뢰할 만한 선택입니다. 클라이언트가 테이블을 다시 쓴 뒤에 실행되기 때문입니다.
상태 기반 방화벽은 올바른 경로도 이길 수 있습니다. 캡처가 이제 응답이 eth0 로 나간다고 보여 주는데 클라이언트가 여전히 시간 초과라면, 호스트가 보내기 전에 패킷을 버리는지 확인하세요. 엄격한 역경로 필터링과 net.ipv4.conf.all.rp_filter 를 1 로 두면, 도착한 인터페이스로 되돌아 라우팅되지 않을 출발지의 패킷을 버립니다. 그것이 바로 방금 만들었다가 고친 비대칭 사례이고, conntrack 상태도 포워딩된 포트에 대해 같은 이야기를 합니다.
마지막 점검은 사람들이 건너뛰는 것입니다. 터널이 내려갔다가 다시 올라온 뒤 조회를 반복하세요. 네 값이 적어 둔 것과 맞아야 합니다. 목적지, 다음 홉, 장치, 선택된 출발지입니다. 그중 하나라도 움직였다면 클라이언트가 테이블을 다시 쓴 것이고, 고칠 곳은 그 훅이지 셸 기록이 아닙니다.