킬 스위치가 작동할 때 열린 TCP 세션은 어떻게 될까?
차단된 패킷은 닫힌 연결이 아닙니다. 세션이 끊긴 구간을 견뎌야 하는지 결정하고, 차단과 복구를 별개의 속성으로 시험하십시오.
터널이 끊기고 킬 스위치가 작동하면, 사분의 삼까지 진행된 다운로드가 멈추거나 즉시 실패한다. 이 두 결과는 보호 수준의 차이가 아니라 적용 방식의 선택에서 나온다. 버려진 패킷은 연결을 기다리게 두고, 거부된 패킷은 연결을 닫고 애플리케이션에 알린다. 어떤 동작을 원하는지는 설계의 문제이고, 그것을 시험하는 일은 별개의 작업이다.
버리기, 거부하기, 재설정은 서로 다르다
트래픽을 버리는 방화벽 규칙은 패킷을 폐기하고 아무것도 돌려보내지 않으므로, 보낸 쪽은 자체 타이머로 계속 재전송한다. TCP 재설정으로 거부하는 규칙은 연결을 즉시 닫고 애플리케이션은 오류를 본다. 대부분의 킬 스위치는 버리기를 택한다. 거부는 정책을 드러내고, 버리기는 죽은 네트워크의 동작과 비슷하기 때문이다.
차단은 소켓을 닫는 것과 같지 않다. 애플리케이션은 여전히 확립 상태의 디스크립터를 쥐고 있고, 패킷만 빠져 있다. 그래서 운영체제가 연결이 존재한다고 주장하는 동안 페이지가 몇 분씩 스피너에 머물 수 있다. 애플리케이션의 메시지에서 추론하지 말고 문서화된 적용 방식을 읽으십시오. 두 동작 모두 네트워크가 죽은 것처럼 보이기 때문이다.
끊긴 구간이 이어지는 동안 애플리케이션은 무엇을 하는가
TCP는 지연을 늘려 가며 재전송하고, Linux의 기본 재시도 예산은 몇 초가 아니라 약 십오 분 만에 소진된다. 그때까지 소켓은 쓸모 있게 열려 있지도, 닫혀 있지도 않다. 자체 keepalive나 요청 시간 제한을 가진 애플리케이션은 더 일찍 포기하는 경우가 많아, 같은 기계의 두 프로그램이 한 번의 장애 동안 다르게 동작한다.
터널이 돌아오면 로컬 소켓은 그대로지만 경로는 아닐 수 있다. 새 공인 출발지 주소는 서버에서 다른 사중주를 만들므로, 반대편의 상태 기반 방화벽은 더 이상 세션과 일치하지 않는다. 클라이언트가 오류를 본 적이 없어도 연결은 죽어 있다.
복구가 필요한지 결정하라
두 가지 계약 중에서 고르십시오. 세션이 짧은 끊김을 견뎌야 한다면 안정적인 주소 지정과 상태를 유지하는 서버가 필요하고, 애플리케이션이 깨끗하게 다시 연결해야 한다면 반복해도 안전한 재시도 로직이 필요하다. 그 중간은 최악의 결과를 낳는다. 서버가 이미 기록한 것을 다시 보내는 클라이언트, 또는 아무도 볼 수 없는 세션의 성공을 보고하는 클라이언트다.
안정적인 주소 지정은 사람들이 잊는 부분이다. 다른 공인 주소에 도착하는 재연결은 클라이언트 소켓이 건강해 보여도 서버 쪽 상태를 무효화하므로, 두 계약 중 어느 것이 각 애플리케이션에 적용되는지 적어 두십시오.
차단과 복구를 따로 확인하라
유출 방지와 세션 생존을 두 가지 속성으로 다루십시오. 하나를 통과해도 다른 하나에 대해서는 아무것도 말해 주지 않는다. 살아남은 세션은 직접 트래픽이 차단되었다는 증거가 아니고, 죽은 세션은 모든 직접 경로가 차단되었다는 증거도 아니다.
ss -tnp state established '( dport = :443 )'
sudo conntrack -L -p tcp --dport 443
sudo tcpdump -ni any 'tcp port 443 and tcp[tcpflags] & tcp-syn != 0'
복구를 관찰할 때는 무해한 시험 작업을 사용해, 중복 제출이 사고가 되지 않게 하십시오. 실제로 본 고장 방식을 기록하십시오. 애플리케이션이 무엇을 표시했는지, 소켓이 살아남았는지, 그리고 그것이 스스로 언제 회복되었는지다.
기대 동작을 적용 규칙 옆에 적고 날짜를 붙이십시오. 그 규칙을 다음에 바꿀 사람은 배포가 두 계약 중 어느 것을 약속했는지 알아야 한다.