터널을 올리고 터널을 소스 인터페이스로 지정해 fe80::1에 ping을 보내지만 아무것도 돌아오지 않습니다. 잊어버린 방화벽 규칙이 아닙니다. 링크 로컬 주소는 그것이 형성된 단일 링크에서만 의미가 있고, 라우팅된 VPN은 그 링크가 아닙니다. 원격 라우터의 fe80::1은 원격 LAN 세그먼트에 있고, 당신은 다른 세그먼트에서 한 홉 떨어져 있으며, IPv6에는 라우터가 링크 로컬 패킷을 전달하는 메커니즘 자체가 없습니다.

fe80 접두사는 범위가 아니라 스코프를 설명한다

링크 로컬 유니캐스트는 fe80::/10이고, 정의하는 속성은 숫자가 아니라 스코프입니다. 주소는 하나의 링크에서만 유효하며, 모든 인터페이스가 자기 식별자로 하나를 형성하므로, 서로 무관한 두 네트워크의 서로 무관한 두 머신이 조금의 충돌도 없이 둘 다 fe80::1에 응답할 수 있습니다. 접두사는 사실상 “어떤 링크에서”라고 말할 뿐이고, 링크 자체는 문맥에서 나옵니다.

호스트에서 그 문맥은 퍼센트 기호 뒤에 붙이는 존, 즉 스코프 ID로, Linux에서는 fe80::1%eth0, Windows와 인터페이스 인덱스를 노출하는 도구에서는 fe80::1%3 또는 fe80::1%12입니다. 커널은 주소를 인터페이스 인덱스와 함께 해석한 뒤 보냅니다. 존을 빼면 목적지가 모호해지므로 스택이 세그먼트를 고를 방법이 없습니다.

라우팅된 터널이 전달할 수 없는 이유

라우팅된 VPN은 자체 주소를 나르는 점대점 인터페이스이며, 보통 터널 안의 unique-local 또는 사설 IPv6 공간의 /64입니다. 원격 LAN은 별도의 링크이고, 터널 엔드포인트가 당신을 대신해 라우팅하고 전달함으로써 도달합니다. 이 둘은 서로 다른 세그먼트이므로 한쪽의 주소는 다른 쪽에서 유효한 목적지가 아닙니다.

전달 규칙은 클라이언트의 변덕이 아니라 표준에 명시되어 있으며, 라우터는 링크 로컬 출발지나 목적지를 가진 패킷을 전달하지 않습니다. 그래서 라우팅 테이블이 올바로 보여도 패킷은 죽습니다. fe80::/64에 대해 터널을 가리키는 경로를 추가하면, 목적지 스코프가 “이 링크만”이라고 말하고 나가는 인터페이스가 그 링크가 아니므로, 표준을 따르는 스택은 그것을 거부하거나 받아들인 뒤 일치하는 모든 패킷을 버립니다.

이웃 탐색은 같은 경계를 강화합니다. 호스트는 링크 로컬 다음 홉을 홉 제한 255의 링크 스코프 멀티캐스트로 보내는 이웃 요청으로 해석하므로, 라우터는 전달된 것을 거부할 수 있습니다. 이것을 터널 너머에서 작동하게 하려면 원격 세그먼트의 탐색을 프록시해야 하며, 그것은 다른 모자를 쓴 Layer 2 브리징입니다.

더 조용한 두 번째 실패가 있고, 그것은 그래도 경로를 강제하려는 사람을 잡습니다—바로 존입니다. 로컬에서 입력하는 존은 터널 인터페이스를 가리키지만, 원하는 주소는 원격 LAN 인터페이스에 묶여 있습니다. 둘은 결코 일치하지 않으므로, 패킷을 먼 쪽 끝에서 올바른 인터페이스로 보낼 수 없습니다.

실제로 실패는 어떻게 보이는가

스코프 실수에 대한 도구 출력은 라우팅이나 방화벽 오류처럼 읽히고, 그래서 사람들이 잘못된 계층에서 반나절을 보냅니다.

What you runWhat you seeWhat it means
ping fe80::1 with no zoneInvalid argument on Linux, or a transmit failure on WindowsThe stack cannot pick an interface for an ambiguous destination
ping -6 -I tun0 fe80::1Destination unreachable, or a silent timeoutThe address is not on the tunnel link, so there is nothing on-link to answer
ssh user@fe80::1 after the tunnel is upHangs, then no route to hostThe SYN never left the machine in a deliverable form; the server logs nothing
ip -6 neigh show dev tun0Empty tableNo neighbor entry can exist for a link-local host that is not on this link
fe80::/64 inside AllowedIPs or route-ipv6Config accepted, traffic still droppedThe tunnel carried the packet; the receiving stack refused to forward it

세 번째 줄이 시간을 가장 많이 낭비합니다, 왜냐하면 출력이 없는 ssh 클라이언트는 수신 서비스 문제처럼 보이기 때문입니다. 들어갈 방법이 있다면 먼 쪽을 확인하고 sshd가 모든 주소에 바인딩되었는지 하나에만 되었는지 확인하세요.

라우팅되도록 만들어진 주소를 사용하세요

터널을 통해 도달해야 하는 모든 것에는 서비스가 바로 그 목적으로 받은 주소를 사용하세요—전역 유니캐스트 주소, 또는 fc00::/7에서 나온 unique-local 주소로, 바로 이 내부 사례를 위해 예약된 범위입니다. 리스너가 실제로 그것을 바인딩하는지, 반환 경로와 호스트 방화벽 규칙을 확인하세요.

추측하지 말고 원격 호스트를 보세요. ip -6 addr show는 존재하는 주소를 나열하고, ss -6 -ltn은 데몬이 무엇을 수신하는지 나열합니다. fe80::에만 바인딩된 서비스는 자기 세그먼트에서만 도달할 수 있으며, 이는 보통 아무도 의도적으로 고르지 않은 기본값이고 관리자의 동의로 바꿀 수 있습니다.

서비스를 정말로 다시 바인딩할 수 없을 때는 브리지를 네트워크 계층이 아니라 애플리케이션 계층으로 올리세요. 원격 호스트에서 라우팅 가능한 주소로 수신하고 링크 로컬 주소로 연결하는 릴레이는 어떤 세그먼트도 확장하지 않고 문제를 해결합니다:

socat TCP6-LISTEN:8080,bind=[fd00:1:2::10] TCP6:[fe80::1%eth0]:80

여기서 존은 올바른 쪽, 즉 그 링크에 실제로 eth0이 있는 호스트에 있습니다. 클라이언트는 fd00:1:2::10과 통신하며 이는 정상적으로 라우팅되고, 릴레이는 링크 로컬 홉을 로컬에서 수행합니다. 같은 요령은 링크 로컬 주소만 광고하는 어플라이언스의 웹 UI나 오래된 BMC에도 통합니다.

브리징이 정말 답일 때, 그리고 무엇을 확인할지

일부 배포는 정말 하나의 공유 세그먼트가 필요합니다—링크 로컬 탐색만 말하는 장치, 멀티캐스트에 의존하는 어플라이언스, 평면 LAN을 재현하는 랩 같은 경우입니다. 그것은 Layer 2 문제이고, 원격 인터페이스에 브리지된 tap 장치나 명시적 브리지 모드를 가진 클라이언트 제품 같은 Layer 2 답이 필요합니다. 그 대가는 터널을 건너는 브로드캐스트와 멀티캐스트 트래픽, 그리고 끝에서 끝까지 작동해야 하는 이웃 탐색입니다.

라우팅된 프로필에 fe80::/64를 추가해 이 문제를 얼버무리면 최악의 상태가 됩니다. 구성은 끝난 것처럼 보이고, 라우팅 테이블에는 항목이 보이며, 모든 패킷은 여전히 둘 다 올바르게 동작하는 두 스택 사이 어딘가에서 버려집니다.

ping이 아니라 인터페이스로 확인하세요. ip -6 addr show tun0은 터널 링크가 자체 링크 로컬 주소를 형성했는지 알려주고, ip -6 route get fe80::1%tun0은 스코프가 지정된 목적지에 대해 커널이 실제로 무엇을 할지 알려줍니다. 커널이 그 인터페이스에서 목적지에 도달할 수 없다고 말하면 어떤 터널 설정도 그것을 바꾸지 못하며, 프로필 편집을 멈출 때입니다.

질문을 정리하는 짧은 순서:

  • 원격 호스트의 주소를 읽고 그것이 fe80::인지 라우팅 가능한 접두사인지 기록하세요.
  • fe80::이면 서비스를 다시 바인딩하거나, 그 호스트에서 릴레이하거나, 세그먼트를 브리지하고, 라우팅 가능하면 경로, 방화벽 또는 바인드 주소를 고치세요.
  • 다시 테스트할 때마다 존을 다시 확인하세요, 복사한 명령은 보통 잘못된 인터페이스를 유지하기 때문입니다.

출처: RFC 4291, IPv6 주소 지정 아키텍처.

관련 글