IPv6 터널 피어로의 ping이 실패하나요? :: 주소를 확인하세요
모두 영인 인터페이스 식별자는 서브넷 라우터 anycast이며 호스트가 아닙니다. ::1과 ::2를 할당하고 프리픽스를 라우팅하며 라우트를 탓하기 전에 multicast를 확인하세요.
IPv6 터널의 한쪽 끝이 다른 쪽으로 ping을 보내지만, 언제나 한 방향만 응답합니다. 인터페이스는 켜져 있고 라우트도 맞아 보이며 로그에도 설명이 없습니다. 할당한 주소는 서브넷 라우터 anycast 주소로 호스트 주소가 전혀 아니며, 두 끝점 링크에서는 배달 대상이 정확히 하나뿐입니다: 보낸 쪽 자신입니다. 어떤 타임아웃 값도 이를 고치지 못합니다. 주소가 생각하는 동작을 하지 않기 때문입니다.
주소를 가리키는 증상
링크의 모든 호스트가 응답하지만 인터페이스 식별자가 모두 영인 호스트만 응답하지 않습니다. 그 형식으로 주소 지정된 패킷은 정의상 서브넷의 라우터로 전달되므로, 지점 간 터널에서는 보낸 기계로 되돌아옵니다. 먼 쪽에서는 도달할 수 없는 피어로 읽히고, 가까운 쪽에서는 침묵으로 읽힙니다. 같은 프리픽스의 다른 식별자로 바꾸면 다른 변경 없이 증상이 사라지며, 라우트를 건드리기 전에 얻어야 할 확인이 바로 이것입니다.
모두 영인 식별자는 anycast로 예약되어 있다
RFC 4291은 모두 영인 인터페이스 식별자를 서브넷 라우터 anycast 주소로 유지하므로, 예를 들어 2001:db8:4a::/64 같은 /64에는 2001:db8:4a::에서 쓸 수 있는 호스트가 없습니다. 이 예약은 제값을 합니다: 라우터 광고와 이웃 탐색이 그 형식을 주소로 삼고, 라우터는 자신이 서비스하는 프리픽스에 대해 응답합니다. 그 값을 터널 끝점에 할당하면 리프에 라우터 역할을 주는 것이므로 아무것도 돌아오지 않습니다. 프리픽스의 다른 식별자는 호스트로 동작하므로 수리는 보통 한 자리입니다.
예약을 터널 끝점에서 차지할 권리가 없는 역할로 취급하세요. 라우트로 피해 갈 기이한 성질이 아닙니다.
호스트 주소를 할당하고 프리픽스를 라우팅하세요
두 끝점에는 ::1 과 ::2 를 고르고, 하나를 다음으로 추가하세요: ip -6 addr add 2001:db8:4a::2/64 dev tun0, 그런 다음 원격 프리픽스에 주소를 주려 하지 말고 라우팅하세요. 2001:db8:4a::/64 에 대한 터널 밖 라우트가 먼 쪽을 도달 가능하게 만듭니다. 주소만으로는 로컬 인터페이스가 설정될 뿐입니다.
전체 터널에는 세 번째 단계가 있습니다. 장치를 통해 전역 unicast용 기본 라우트를 넣는 것으로, 모든 것을 터널로 보내는 IPv6 판입니다. 이것을 빼면 IPv4가 터널 안을 지나는 동안 IPv6는 물리 링크를 계속 쓰므로, 호스트는 덮였다고 믿은 트래픽을 정확히 누출합니다. 다음으로 확인하세요: ip -6 route get 2001:4860:4860::8888 그리고 답을 가정하지 말고 어느 장치를 지목하는지 읽으세요.
multicast는 라우팅 전에 거부된다
Android는 VpnService.Builder 의 주소와 라우트를 LinkAddress을 통해 검증하며, 그 생성자는 multicast를 곧바로 거부합니다. 라우트로 multicast 프리픽스를 주면 결과는 라우트가 아니라 잘못된 LinkAddress 매개변수 실패이며, 이는 네트워크가 아니라 검증의 답입니다. 이 거부는 매체와 맞습니다: 지점 간 tun 장치에는 링크 계층 multicast가 없으므로 그 위의 그룹 라우트에는 설치할 배달 모델이 없습니다. 그룹 주소는 손으로 구성되지 않고 스택 자신이 만들고 소비합니다.
IPv6 all-nodes와 solicited-node 주소도 같은 규칙에 속합니다. 인터페이스가 그것들을 나르는 것은 스택이 거기에 두었기 때문이며, 정책이 의도했기 때문이 아닙니다.
터널이 대신 나를 수 있는 것
터널을 가로지르는 multicast 탐색 을 옮기려면 그룹 멤버십을 이해하는 계층이 필요합니다: Ethernet 세그먼트를 제시하는 TAP 브리지, 애플리케이션 수준 릴레이, 또는 어느 피어로 복제할지 명시적으로 지시받은 라우팅 프로토콜입니다. VpnService 모델에는 그중 어느 것도 없으며, 애플리케이션은 패킷을 읽고 쓸 뿐 터널을 위해 그룹에 가입하는 호출이 없습니다. 그룹을 이해하는 구성 요소를 추가하거나 설계에서 그 요구를 빼세요.
반대로 unicast는 위의 주소와 라우트 외에는 아무것도 더 필요로 하지 않으며, 그래서 보통 터널이 그것을 나른다고 기대하고 나서 탐색 프로토콜이 실패하면 터널을 탓합니다.
무엇이든 할당하기 전 세 가지 확인
주소가 anycast 형식이 아님을, multicast가 아님을, 그리고 프리픽스가 장치에 할당된 것만이 아니라 라우팅되었음을 확인하세요. 그런 다음 테스트를 실제 호스트인 목적지로 보내세요. anycast 주소를 향한 ping은 보낸 쪽을 측정할 뿐 경로에 대해 아무것도 알려주지 않습니다. 그 세 가지 확인을 변경 기록에 남겨 다음 배포가 다시 발견하지 않게 하세요.
플랫폼이 한 번도 설치하지 않은 라우트는 더 오래 기다려도 디버그할 수 없고, 한 번도 호스트였던 적 없는 주소는 더 나은 ping으로 고칠 수 없습니다.