이 설정은 앱별 스위치처럼 보이기 때문에 사람들은 클라이언트를 WireGuard 인터페이스에 바인딩하고 그 클라이언트만 터널을 쓸 것이라 기대합니다. 바인딩이 실제로 하는 일은 소스 주소를 고르는 것입니다. 그다음 커널은 목적지의 경로를 조회하고, 평범한 기본 경로를 찾아, 터널 주소를 붙인 채 패킷을 물리 링크로 내보냅니다. 그 소스 주소를 위해 선택된 경로만이 의도를 완성합니다.

이 메커니즘은 터널의 트래픽만 사용해야 하는 라우팅 테이블과, 일치하는 소스를 그리로 보내는 규칙, 두 부분으로 나뉩니다.

바인딩은 소스 주소만 정한다

리눅스는 정책 규칙이 그 조회를 다른 곳으로 돌릴 기회를 얻은 뒤 라우팅 테이블에서 목적지를 조회해 출력 인터페이스를 고릅니다. 규칙은 소스 주소, 방화벽 마크, 입력 인터페이스, UID, 심지어 포트로도 선택할 수 있으며, 각각은 모든 트래픽이 아니라 이 트래픽이라고 말하는 또 다른 방법입니다. VPN 클라이언트 설정은 터널 경로가 담긴 테이블을 고르고, 규칙은 어느 트래픽이 그 테이블을 참조할 수 있는지 고릅니다. 바인딩만으로는 둘 다 제공되지 않습니다.

그래서 이 실패는 이상하게 보입니다. 앱은 분명히 터널 주소를 쓰고 있고, 터널은 분명히 올라와 있고, 트래픽은 분명히 잘못된 인터페이스로 나가고 있습니다. 모든 문장이 참이며, 함께 보면 주소와 경로를 연결한 것이 아무것도 없는 체계를 설명합니다.

터널에 전용 테이블을 준다

wg-quick은 프로필이 말하는 곳에 경로를 설치합니다. [Interface] 아래에 Table = 40를 추가하면 경로가 메인 테이블이 아니라 테이블 40으로 이동합니다. 인터페이스를 올려 ip -4 route ls table 40로 터널의 경로를, ip -4 route get 10.66.127.142로 커널이 지금 그중 하나를 어떻게 해석하는지 확인하십시오. 경로가 전용 테이블에 있으면 메인 테이블은 나머지 모두를 위해 계속 동작합니다.

넓은 프리픽스를 맞추는 대신 IPv6에도 같은 일을 하십시오. ip -6 rule add from fd00::2/128 lookup 40는 주소 하나를 고정하고, fc00::/8는 호스트의 다른 인터페이스와 충돌해 의도보다 넓게 일치하는 규칙을 만들 수 있습니다.

소스 규칙을 추가하고 카운터를 본다

다음으로 ip -4 rule add from 10.66.127.142/32 lookup 40로 두 부분을 연결하고, 같은 주소를 WireGuard 인터페이스에 붙여 둡니다. 두 규칙을 PostUp에 넣으면 다시 연결할 때 복원됩니다. 설정이 아니라 실제 요청으로 확인하면 ip route get 1.1.1.1 from 10.66.127.142가 터널 장치를 지목하고, curl --interface wg0 ifconfig.me가 집 주소가 아니라 터널의 주소를 보고해야 합니다.

그래도 실패하면 ip -s rule를 읽으십시오. 존재하지만 한 번도 일치한 적 없는 규칙은 카운터가 영으로 나오며, 이것이 잘못된 규칙과 규칙이 아예 없는 경우를 구분합니다. 그 명령 하나로 앱이 인터페이스 설정을 무시했는지에 대한 추측이 크게 줄어듭니다.

반대의 경우: SSH를 터널 밖에 둔다

반대 문제도 흔하며, wg-quick이 기본 경로를 소유하고 있어서 서버로 가는 SSH 세션이 중간에 끊깁니다. 그 규칙은 낮은 우선순위 번호에 있어 예외는 그보다 먼저 평가되어야 합니다. ip rule add dport 22 ipproto tcp table main priority 123는 최신 iproute2에서 그렇게 하지만, 선택자를 쓸 수 없는 곳에서는 nftables에서 흐름에 표시를 하고 대신 그 표시를 일치시키십시오.

돌아오는 경로도 확인하십시오. 연결이 맺어진 뒤 조용해지는 SSH 세션은 보통 비대칭 라우팅이며, 한 방향은 터널로, 다른 방향은 물리 인터페이스로 나갑니다. 서버 주소에 대한 ip route get가 응답이 어느 쪽으로 갈지 알려 줍니다.

테이블 번호, 소스 규칙, 예외를 프로필 자체에 기록하십시오. 셋은 하나의 설계에 속하며 함께 편집될 것입니다.

관련 글