분할 터널 프로필 두 개, 사설 프리픽스 두 개, 그리고 둘 다 자신의 것이라고 주장하는 호스트 한 대가 있다. 증상은 깔끔한 실패로 나타나는 경우가 드물어서, 어떤 서비스는 월요일에는 동작하고 두 번째 클라이언트가 다시 연결한 뒤에는 시간 초과가 나며 재부팅 후에는 다시 동작한다. 클라이언트를 연결한 순서가 결과를 결정하지 않고, 클라이언트 화면의 행 순서도 마찬가지다. 다음 점검을 순서대로 수행하고 맞지 않는 첫 지점에서 멈추어야 하는데, 뒤 단계는 앞 단계가 참일 때만 의미가 있기 때문이다.

1. 목적지와 출발지를 적는다

실패하는 요청이 향하는 정확한 주소에서 시작하고, 호스트 이름이나 애플리케이션 이름에서 시작하지 않는다. 이름을 한 번 확인해 모든 응답을 기록하고, 실패하는 흐름이 실제로 쓰는 것을 고른다. 그다음 같은 흐름의 로컬 주소를 적어야 하는데, 출발지 주소에 따라 어떤 정책 규칙이 맞는지, 따라서 어느 테이블을 보는지가 달라지기 때문이다.

여러 A 레코드 중 하나로 가는 요청이 실패하는데 형제 주소는 성공할 수 있고, 이는 불안정한 터널처럼 보이지만 실제로는 서로 다른 두 경로다. 목적지가 여러 응답을 가진 이름이라면 무언가를 바꾸기 전에 각 응답을 따로 시험한다.

2. 커널에 어떤 경로를 골랐는지 묻는다

경로 테이블을 읽고 답을 추론하지 않는다. 스택이 던지는 것과 같은 질문을 같은 출발지 주소로 던지는데, Linux에서는 ip route get 10.20.4.10 from 10.8.0.2, PowerShell에서는 Find-NetRoute -RemoteIPAddress 10.20.4.10 이다. 출력은 실제로 사용될 경로를 알려 주며, 그것은 테이블을 읽고 예상한 것과 다른 경우가 많다.

일치하는 경로 중에서는 보통 더 구체적인 프리픽스가 이기며, 둘 모두에 속한 주소라면 /24가 /16을 이긴다. 같은 길이의 일치끼리는 메트릭이 낮은 쪽이 이기고, 내려간 링크에 설치된 경로는 건너뛴다. 같은 /24를 같은 메트릭으로 밀어 넣는 두 터널은 다른 경우인데, 커널이 두 경로를 모두 유지하고 그 사이에서 고르므로 클라이언트가 연결된 순서를 따르지 않고 결과가 번갈아 나타날 수 있다. 월요일에는 되고 화요일에는 실패하는 패턴을 만드는 것이 바로 이 상황이며, 다른 순서로 다시 연결해도 달라지지 않는다.

3. 정책 규칙이 조회를 다른 곳으로 돌렸는지 확인한다

경로 테이블을 보기 전에 커널은 자기 정책 규칙을 훑는다. 규칙은 특정 출발지, 사용자, 방화벽 표시에서 온 트래픽을 완전히 다른 테이블로 보낼 수 있으므로, 메인 테이블의 이기는 프리픽스가 그 흐름에서는 한 번도 조회되지 않을 수 있다. ip rule show 는 그것들을 평가 순서대로 나열하고, ip route show table 100 는 선택된 테이블에 실제로 무엇이 있는지 보여 준다.

여기에는 두 가지 함정이 있다. 빈 테이블을 가리키는 규칙은 다음 규칙으로 빠지는 조회를 만들어 아무것도 하지 않는 것처럼 보인다. 다른 하나는 우선순위 번호 자체인데, 규칙은 오름차순으로 읽히고 내장 값은 0 local, 32766 main, 32767 default 이다. 32767보다 작은 번호의 규칙은 모든 것을 잡는 기본 규칙보다 먼저 조회된다. 32767보다 큰 번호의 규칙은 그 뒤에 자리하며 이전 테이블이 아무것도 응답하지 않을 때만 도달하는데, main의 평범한 기본 경로가 이를 막으므로 실제로는 결코 도달하지 못하고 설치된 것처럼 보이면서 조용히 아무것도 하지 않는다. 클라이언트가 규칙과 경로를 썼다면 둘 다 확인하고 다시 연결한 뒤에 다시 확인해야 하는데, 다시 쓰인 프로필이 다른 우선순위의 두 번째 규칙을 추가할 수 있기 때문이다.

4. 라우팅 동률과 중복된 주소 계획을 구분한다

때로는 프리픽스가 전혀 문제가 아니다. 두 사이트가 모두 192.168.1.0/24 를 쓴다면 같은 주소가 서로 다른 두 호스트를 가리킨다는 뜻이고, 어떤 경로도 둘을 구분할 수 없다. 두 응답 중 하나로 가는 호스트 경로는 다른 사이트가 같은 이름에 응답할 때까지만 동작하고, 그때 예외가 조용히 결함이 된다.

단서는 목적지 주소가 두 경로에서 동일하고 의도한 소유자만 다르다는 점이다. 이것은 라우팅 조정이 아니라 주소 계획의 결정이므로, 한쪽을 다시 번호 매기거나 한쪽을 변환 게이트웨이 뒤에 두거나 자기 이름을 스스로 확인하는 프록시를 통해 두 번째 사이트에 도달해야 한다. 기본 경로를 낮추거나 호스트 예외를 쌓는 것은 충돌을 다른 곳으로 옮길 뿐이다.

5. 확인자가 경로와 일치하는지 확인한다

잘못된 사설 주소로 확인되는 이름은 라우팅 충돌의 모든 증상을 만들고 그 원인은 하나도 만들지 않는다. 호스트가 받는 응답과 목적지가 실제로 쓰는 주소를 비교하고, 어떤 확인자가 응답했는지 점검한다. 터널이 확인자를 밀어 넣는다면 클라이언트는 터널을 쓰는 흐름에 대해 그것을 설치해야 하고, 그렇지 않으면 호스트는 로컬 확인자에게 계속 물어보며 그 확인자는 검색 도메인이나 캐시된 레코드에서 응답할 수 있다.

확인자에게 직접 질의하고 응답한 서버를 적는다. 짧은 TTL의 캐시 응답은 다시 연결한 뒤 첫 요청이 다섯 번째와 다르게 동작하는 이유도 설명해 준다.

6. 다시 연결하고 적용된 상태를 살핀 뒤 두 흐름을 시험한다

수정한 뒤에는 프로필 편집기를 믿는 대신 다시 연결하고 클라이언트가 실제로 무엇을 설치했는지 살핀다. 규칙과 테이블, 그리고 그 결과로 나오는 ip route get 응답을 다시 읽는다. 두 번째 클라이언트가 연결할 때 자기 경로를 다시 설치 해 충돌을 되살릴 수 있으므로, 상태 점검은 마지막 클라이언트가 연결한 뒤에 해야 하고 그 전에 해서는 안 된다.

시험할 것은 하나가 아니라 두 흐름으로, 예전에 실패하던 요청과 다른 터널을 써야 하는 자원이다. 사설 트래픽을 모두 한 연결로 옮기면 첫 시험은 통과하지만 두 번째가 깨지며, 이를 잡아내는 것은 짝지은 시험뿐이다. 남겨 두는 예외마다 목적지와 이유를 기록해 두어야 다음 사람이 의도한 호스트 경로와 남은 것을 구분할 수 있다.

관련 글