건강한 VPN 출구 두 개, 이미 실행 중인 긴 업로드 하나, 그리고 다음 연결이 다른 터널을 써야 한다는 요구가 있습니다. 이를 충족하는 방법은 두 가지이며, 살아 있는 게이트웨이에서 안전한 것은 하나뿐입니다. 기본 경로를 바꾸면 업로드에 속한 패킷까지 모든 패킷이 이동합니다. 계획된 드레인은 새 연결의 선택만 바꾸고 추적된 흐름은 시작한 경로에 그대로 둡니다.

출구를 바꾸는 두 가지 방법

경로 교체는 명령 하나이고 몇 초 만에 되돌릴 수 있어 장애 상황에서 사용됩니다. 다만 구분하지 않아, 기존 업로드의 패킷이 갑자기 다른 터널로 나가고, 공인 출발지 주소도 변환 상태도 달라집니다.

원격 끝이 출발지 주소로 흐름을 추적한다면 업로드는 인식되지 않게 될 수 있습니다. 드레인은 연결마다 한 번 결정하고 이를 저장해 이를 피하므로, 기존 업로드는 끝날 때까지 자기 출구를 유지합니다. 이것이 이 작업의 가치 전부이며, 원격 끝은 해석해야 할 변화를 전혀 보지 못합니다. 이미 알고 있는 연결과 일치하는 패킷을 계속 받습니다.

대가는 복잡성으로, 라우팅 테이블 두 개, 올바른 훅에서 실행되는 분류기, 그리고 머신에서 이를 쓰는 다른 모든 것과 조정해야 하는 마크가 필요합니다.

각 출구에 자체 테이블을 주십시오

출구마다 라우팅 테이블을 예약하고 두 선택에 서로 다른 마크 값이나 비트를 배정합니다. 각 테이블에는 이름만이 아니라 역할에 맞는 경로가 필요하고, 해당 사항이 없을 때의 의도된 실패 결과도 필요합니다.메인 테이블로 조용히 떨어지는 빈 테이블 — 아무도 선택하지 않은 출구로 트래픽이 나가는 방식입니다.

ip rule add fwmark 0x10/0x10 table 101
ip rule add fwmark 0x20/0x20 table 102
ip route add default via 192.0.2.1 dev wg-a table 101
ip route add default via 198.51.100.1 dev wg-b table 102

각 테이블 끝에 blackhole 경로를 추가해, 일치를 찾지 못한 조회가 선택하지 않은 기본값으로 도망가는 대신 크게 실패하게 하십시오.

한 번만 선택하십시오, 첫 패킷에서

연결 추적이 존재한 뒤, 중요한 경로 조회 전에 분류합니다. 새롭고 분류되지 않은 LAN 연결은 출구를 골라 연결 상태에 저장합니다. 이후 패킷에서는 정책 라우팅이 읽는 패킷 마크로 저장된 값을 복원합니다.

미묘한 부분은 새롭다는 것의 의미입니다. conntrack은 응답이 보이기 전 초기 패킷과 재전송에 대해 여전히 NEW를 보고할 수 있으므로, 그 상태만 보는 분류기는 이미 내린 선택을 덮어쓸 수 있습니다. 출구를 할당하기 전에 그 연결에 저장된 출구가 없는지 확인하십시오.

nftables는 패킷 마크와 연결 마크를 분리해 유지하며, 메타정보 안내서가 둘 사이의 명시적 복사를 문서화합니다. 연결 마크가 규칙과 일치하는 패킷 마크가 저절로 되지는 않으며, 이것이 신중하게 작성한 분류기가 효과가 없는 가장 흔한 이유입니다.

복원 범위를 의도한 방향과 트래픽으로 제한하려면, 인터넷 출구 마크를 돌아오는 패킷에 적용할 때 응답이 LAN이 아니라 출구 쪽으로 갈 수 있고 증상은 방화벽 문제처럼 보이는 단방향 연결임을 기억하십시오. 방화벽 규칙을 건드리기 전에 응답 경로를 읽으십시오. 패킷은 라우팅되고 있지만 발신자에게 돌아가지 않을 뿐입니다.

드레인의 네 단계

  1. A를 건드리지 않고 B를 준비하십시오. 라우팅, 포워딩, 권한 부여, NAT, 반환 경로를 갖추고, 게이트웨이의 기존 구성 소유자를 통해 그 테이블과 선택 정책을 설치하십시오.

  2. 분류기를 전환해 새롭고 분류되지 않은 연결이 B를 선택하게 하고 저장된 선택은 보존합니다. 원자적 nftables 트랜잭션은 옛 상태를 지워야 하는 창을 피합니다.

  3. A의 흐름이 끝날 때까지 A를 켜 두십시오. 그 인터페이스, 테이블, 원격 출구, NAT 매핑은 여전히 그 흐름의 일부이며, NAT 규칙을 편집해도 이미 존재하는 바인딩은 다시 만들어지지 않습니다.

  4. 드레인 조건이 충족되면 A를 퇴역시키되, 판단은 한 번의 조용한 구간이 아니라 연결 상태와 애플리케이션 동작으로 합니다.

드레인이 약속할 수 없는 것

브라우저 요청은 새 전송 연결이 아니며, 풀링은 옛 연결로 요청을 계속 보냅니다. 반대로 UDP 흐름은 conntrack에서 늙어 사라질 수 있고 이후 패킷은 새로 분류됩니다. 드레인은 추적된 흐름을 따르며, 애플리케이션이 생각하는 세션을 따르지 않습니다.

A의 흐름이 끝나기 전에 A가 실패하면 저장된 마크가 그들을 구하지 못합니다. B를 통해 다시 연결되거나 아예 연결되지 않습니다. 계획된 드레인은 원래 경로가 건강한 동안 연속성을 사는 것이며, 독립된 출구 사이의 상태 복제가 아닙니다.

양쪽 절반을 모두 검증하십시오

변경 전에 오래 유지되는 허용된 연결을, 변경 후에 진짜 새 연결을 시작하십시오. 각각이 어느 터널을 쓰는지, 원격 끝이 어떤 공인 출발지 주소를 보는지 확인한 다음 반환 트래픽이 돌아오는지 점검하십시오.

새 선택이 나타나게 하려고 conntrack 테이블을 비우지 마십시오. 그것은 드레인이 보존해야 할 상태를 정확히 파괴하며, 통제된 마이그레이션을 깨끗해 보이는 테스트와 함께 장애로 바꿉니다.

관련 글