터널은 올라와 있고 핸드셰이크는 두 분마다 일어나며, 반대편에서는 정확히 한 주소만 응답한다. 피어의 터널 주소로 가는 ping은 되지만 그 뒤에 있는 것은 아무것도 되지 않는다. 누군가 인터페이스 설정을 읽고 호스트 프리픽스를 보고 마스크가 잘못됐다고 결론짓는다. /24로 넓히면 ping이 잠시 고쳐지고 그다음 다른 것이 깨진다. 프리픽스는 애초에 원인이 아니었고, 빠져 있던 경로는 마스크가 제어하는 경로가 아니다.

인터페이스 프리픽스가 실제로 만드는 것

Linux에서 인터페이스에 주소를 할당하면 그 프리픽스에 대한 연결 경로가 만들어진다. 호스트 프리픽스를 할당하면 연결 경로는 주소 하나만 덮는다. /24를 할당하면 256개를 덮고, 그 각각이 이제 그 링크를 통해 도달 가능한 것으로 취급된다.

ip -4 addr show dev wg0
ip -4 route show dev wg0
ip route get 10.80.7.1

호스트 프리픽스는 지점 간 터널에 아주 정상적인 선택이다. 반대편에 피어가 정확히 하나뿐이기 때문이다. 세 번째 명령이 사용자의 질문에 답한다. 그 목적지에 커널이 어느 인터페이스를 쓸지 알려 주고, 어떤 경로도 일치하지 않으면 유용한 것을 아무것도 보여 주지 않는다.

이것이 증상의 전부다. 주소 하나가 응답하는 것은 그 주소에 대한 연결 경로가 있기 때문이거나, 피어의 허용 목록에 우연히 들어 있기 때문이다. 나머지에는 경로가 없고 WireGuard가 관여하기 전에 버려진다. 터널은 내내 건강하며, 그래서 핸드셰이크 카운터가 계속 안심되는 모습을 보인다.

AllowedIPs는 하나의 이름 아래 두 규칙이다

WireGuard의 피어별 허용 목록은 동시에 두 가지 일을 하고, 설정 문법 때문에 하나처럼 보인다. 인바운드에서는 피어가 제시할 수 있는 출발지 주소를 허용한다. 아웃바운드에서는 가장 구체적인 일치를 찾아 패킷을 어느 피어로 보낼지 고른다.

두 일 모두 라우팅이 아니다. 커널은 WireGuard가 패킷을 보기 전에 그 패킷이 터널 인터페이스에 속한다고 판단해야 하고, 그 판단은 라우팅 테이블에서 온다. 넓은 허용 목록을 가진 피어 항목은 스스로 경로를 설치하지 않는다.

그래서 설정이 완전해 보이면서 비대칭으로 동작할 수 있다. 경로가 있으니 클라이언트는 반대편으로 보내지만, 반대편의 허용 목록이 클라이언트의 출발지를 허용하지 않거나 반대편에 돌아오는 경로가 없어서 응답은 끝내 도착하지 않는다. 두 방향은 별개의 결정이고 실패 방식도 별개다. 어느 쪽을 시험 중인지 적는 것이 진단의 절반이다.

경로는 어디에서 오는가

wg-quick을 쓰면 경로는 각 피어의 허용 목록에서 자동으로 생성된다. Table = off을 설정해 직접 관리하기로 한 경우는 예외다. 이것이 도구가 문서화한 동작이고, 명시적 경로 지시가 없는 설정도 동작하는 이유다.

sudo wg show wg0 allowed-ips
ip route show | grep wg0
sudo wg-quick strip wg0

허용 목록과 실제로 존재하는 경로를 비교하라. 서브넷 전체를 허용했는데 호스트 경로만 만들어졌다면 도우미가 한 번도 실행되지 않았거나, wg과 ip로 인터페이스를 직접 관리하고 있는 것이며, 그 경우 경로를 만들어 주는 것이 아무것도 없다.

직접 관리할 때 경로는 한 줄이고 형태가 분명하다. 목적지를 인터페이스로, 링크가 지점 간이므로 게이트웨이는 없다. 이것을 추가하는 것은 나쁜 프리픽스에 대한 우회가 아니라, 라우팅을 스스로 맡기로 한 설계의 빠진 절반이다.

프리픽스를 넓혀도 피어 항목은 늘지 않는다

솔깃한 수정은 주소를 /24로 바꿔 연결 경로가 서버의 LAN을 덮게 하는 것이다. 되는 것처럼 보이며, 되는 것처럼 보이는 이유는 연결 경로가 이제 일치하기 때문이지 WireGuard가 새로 무언가를 배웠기 때문이 아니다.

또한 그 범위 전체를 그 링크를 통해 직접 도달 가능하다고 주장한 셈이다. 다른 피어에 속한 주소나 실제로는 서버 뒤에 있는 LAN의 주소까지 포함된다. 그 주소로 가는 트래픽은 이제 터널로 들어가고, 반대편으로 나올지는 서버 자체의 라우팅과 허용 목록에 달려 있다.

암호 쪽은 어느 경우에도 영향받지 않는다. WireGuard는 피어를 고르기 위해 목적지를 덮는 허용 목록 항목이 여전히 필요하고, 반대편은 당신의 출발지를 덮는 항목이 여전히 필요하다. 더 넓은 인터페이스 프리픽스는 둘 다 제공할 수 없다.

무엇이든 바꾸기 전에 양방향을 확인하라

양 끝을 따로 다루고 각각이 무엇을 말하는지 적어라. 클라이언트에서는 경로와 피어 항목, 서버에서는 거울 이미지와 자체 반환 경로다.

ip route get 192.168.70.20
sudo wg show wg0 allowed-ips
sudo wg show wg0 latest-handshakes
sudo tcpdump -ni wg0 -c 10

방향에 대한 논쟁을 끝내는 것은 캡처다. 나가는 패킷이 터널 인터페이스에 나타나는데 서버가 아무것도 기록하지 않으면 원격 끝이 거부하는 것이고, 보통 출발지가 그 허용 목록 밖에 있기 때문이다. 아무것도 나타나지 않으면 경로가 없거나 다른 곳을 가리킨다.

그다음 더 좁은 쪽을 고친다. 서버 쪽에 클라이언트 주소에 대한 허용 목록 항목, 클라이언트 쪽에 목적지 서브넷에 대한 항목이 일반적인 형태이며 인터페이스 프리픽스는 건드리지 않는다. 프리픽스를 넓히는 것은 주소 계획이 정말로 그 링크에서 공유 서브넷을 원할 때만 하고, 디버깅 단계가 아니라 계획 변경으로 하라.

관련 글