VPN 방화벽 훅이 같은 규칙을 두 번 추가하는 이유
재연결이 훅을 다시 실행할 수 있으므로 원하는 상태를 기준으로 설계하세요. 전용 체인, 삽입 전 테스트, 직렬화된 변경, 좁은 철거입니다.
훅은 처음에는 작동하고, 세 번의 재연결 뒤에는 체인에 같은 규칙의 사본이 세 개 남습니다. 아무것도 요란하게 실패하지 않았습니다. 스크립트는 실행될 때마다 시킨 대로 했을 뿐입니다. VPN 훅은 여러 번 실행될 수 있는 구성 작업이므로 소유자, 원하는 상태, 직렬화된 변경이 필요합니다. 이 순서로 진행하면 중복이 멈춥니다.
규칙을 쓰기 전에 소유자를 정하세요
규칙을 하나도 쓰기 전에 이 통합이 어떤 체인이나 테이블을 소유하는지 정하세요. 훅이 만들고 비우는 전용 체인이 소유권의 가장 분명한 형태입니다. 정리할 때 다른 사람의 정책을 건드리지 않고 그 체인을 제거할 수 있기 때문입니다. 공유 체인에 규칙을 추가해야 한다면 주석으로 표시해 나중에 검색할 때 정확히 당신의 규칙만 찾을 수 있게 하세요. 소유권이 철거를 안전하게 만들고, 철거가 바로 조용히 실패하는 부분입니다.
iptables -N VPN_HOOK 2>/dev/null || true
iptables -C INPUT -j VPN_HOOK 2>/dev/null || iptables -I INPUT -j VPN_HOOK
iptables -S VPN_HOOK
여기서 주석은 장식이 아닙니다. 자기 규칙을 지우는 것과 우연히 비슷해 보이는 규칙을 지우는 것의 차이이며, 저장된 규칙 집합에 남습니다. 주석을 변수에 한 번 쓰고 추가, 테스트, 삭제하는 모든 명령에서 같은 문자열을 사용하세요.
다시 추가하는 대신 원하는 상태를 테스트하세요
터널이 올라와 있는 동안 무엇이 있어야 하는지 적으세요. 어떤 인터페이스, 어떤 출발지와 목적지, 어떤 프로토콜과 어떤 포트인지입니다. 그다음 각 규칙을 테스트와 그 뒤의 삽입으로 표현해, 두 번째 실행에서 규칙을 찾고 아무것도 하지 않게 하세요. 규칙이 있으면 검사 명령은 영으로 끝나며, 그것이 바로 스크립트에 필요한 신호입니다. iptables 참조에 여기서 쓰는 검사, 추가, 삽입 형식이 문서화되어 있습니다.
iptables -C VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT ||
iptables -A VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
위치에 주의하세요. 규칙을 검사해 맨 앞에 삽입하면 예전에 먼저 오던 의도적 거부보다 허용을 앞으로 옮길 수 있어, 두 번째 실행은 아무것도 추가하지 않으면서 동작을 바꿉니다. 자기 체인 안에서는 끝에 추가하고, 그 체인으로의 점프 위치로 순서를 제어하세요. 체인 내부의 순서가 중요하면 규칙마다 덧대지 말고 알려진 목록에서 체인을 다시 만드세요.
필요한 규칙을 안정적인 테스트로 표현할 수 없다면 멈추세요. 보통 원하는 상태가 아직 모호하다는 뜻입니다.
유지되기를 바라지 말고 변경을 직렬화하세요
훅 호출 두 개가 겹칠 수 있고, 둘 다 상대가 추가하기 전에 규칙이 없음을 볼 수 있습니다. xtables의 대기 옵션은 명령이 잠금을 기다리게 하지만, 검사 후 추가하는 순서를 두 명령에 걸쳐 원자적으로 만들지는 않습니다. 전체 작업을 자신의 잠금으로 직렬화하거나, 선언한 배치를 하나의 트랜잭션으로 적용하는 관리자를 사용하세요. nftables가 후자를 할 수 있으며, 사용 가능한 호스트에서 그것을 선호하는 이유 중 하나입니다.
flock /run/vpn-hook.lock /usr/local/sbin/vpn-firewall-apply
nft -f /etc/nftables/vpn-hook.nft
어떤 메커니즘을 선택하든 임계 구역을 짧게 유지하고 재진입 가능하게 만드세요. 중간에 실패한 훅은 다시 실행해도 안전해야 하므로, 결과를 기록해 반복 실행이 규칙 수에서 추정되지 않고 저널에 보이게 하세요. 서로 다른 두 감독자가 훅을 호출할 수 있다면 먼저 그것을 고치세요. 어떤 잠금도 두 소유자를 고치지 못합니다.
당신이 소유한 것만 철거하세요
철거는 교체 연결을 그것이 은퇴시킨 연결과 구분해야 하고, 결코 정상적인 정리를 받지 못하는 이벤트를 견뎌야 합니다. 추가할 때 사용한 같은 식별자로 삭제하고, 정리를 간단히 하려고 공유 체인을 비우지 마세요. 강제 중지 뒤에는 다운 훅이 실행됐다고 가정하지 말고 다음 시작 시 조정 단계를 실행하세요.
iptables -D VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
iptables -F VPN_HOOK
ip -brief link show type tun
인터페이스 수명도 설계의 일부입니다. 재연결로 다른 이름의 장치가 생길 수 있어, 두 번째 터널 이름을 고정한 규칙은 여전히 유효해 보이면서 낡아집니다. 연결 자체가 드러내는 정체성을 선호하고, 실행할 때마다 다시 읽으세요. 세 이벤트를 따로 테스트하세요. 반복 연결, 교체 연결, 종료입니다. 허용된 트래픽은 셋 모두를 중복 없이 통과해야 하고, 무관한 서비스는 그대로여야 합니다.
훅에 소유자, 추가하는 각 규칙의 테스트, 하나의 직렬화된 경로, 자기 상태만 제거하는 철거가 있을 때 이 여정은 끝납니다. 두 번 실행해도 안전한 훅은 한 번 영리한 훅보다 가치 있습니다.