OpenVPN을 위한 macOS pf 킬 스위치: 닫히는 규칙
pf 규칙 집합은 터널이 내려가 있는 동안 직접 트래픽을 차단합니다. 클라이언트에서 서버로 가는 경로를 남기고, 터널을 끈 상태에서 차단을 증명하십시오.
macOS에서 킬 스위치는 그 뒤에 있는 패킷 필터 정책만큼만 좋으며, pf는 그 정책을 집행하는 부분입니다. 정책은 동시에 두 가지 상반된 일을 해야 합니다—터널이 존재할 수 있도록 클라이언트가 자기 서버에 닿게 하고, 나머지 모든 것이 직접 나가지 못하게 막는 것입니다. 공개된 규칙 집합 대부분은 두 번째를 해내고 첫 번째를 잊어버리므로, 기계는 보호를 얻는 대신 연결을 잃습니다. 제대로 된 버전은 끝점, 해석기, 터널만 지목하고 그 이상은 말하지 않습니다.
패킷 필터가 결정할 수 있는 것과 없는 것
pf는 인터페이스, 주소, 프로토콜 번호, 포트를 보고 거기서 멈춥니다. 어떤 프로세스가 소켓을 열었는지는 결코 알지 못하므로, 한 프로그램을 위해 쓴 허가는 같은 포트에 닿을 수 있는 모든 프로그램의 허가가 됩니다. 관대한 UDP 예외가 킬 스위치를 다시 평범한 네트워크로 되돌리는 방식이 그렇습니다. 애플리케이션을 아는 차단은 클라이언트나 시스템 확장의 몫이며 이 파일의 몫이 아닙니다.
필터는 경로도 만들지 않습니다. 클라이언트가 끊기면 기본 경로가 여전히 죽은 터널을 가리킬 수 있고, pf는 그것을 Wi-Fi로 조용히 되돌아가는 대신 차단된 패킷으로 바꿉니다. 차단은 의도된 결과이며 피해 가야 할 고장이 아닙니다.
결과를 정하는 것은 규칙의 문구보다 순서인 경우가 더 많습니다. quick 없이는 pf가 일치한 뒤에도 계속 평가하고 마지막으로 일치한 규칙이 이기므로, 아래쪽의 넓은 통과가 위쪽의 신중한 예외를 무효화합니다. 통과에 quick을 표시하면 첫 일치가 확정되며, 정책 작성자가 보통 의도하는 바가 이것입니다.
먼저 인터페이스와 끝점의 사실을 읽으십시오
무선 인터페이스는 Mac마다 같은 방식으로 번호가 매겨지지 않고, 터널 장치는 부팅 사이에 바뀔 수 있는 번호를 받습니다. 없는 장치를 지목하는 규칙은 파싱 때 실패해 시끄럽고 잡기 쉽지만, 잘못된 기존 장치를 지목하는 규칙은 깨끗이 파싱되고 막으려던 트래픽을 허용합니다.
클라이언트가 연결된 동안 사실을 모으십시오—터널 장치는 그때만 존재합니다. 기본 경로를 가진 인터페이스, 클라이언트가 만든 장치, 그리고 클라이언트가 접속하는 서버의 주소와 포트가 필요합니다. 바로 그 마지막 값이 대부분의 규칙 집합이 빠뜨리는 값이며, 그것을 빠뜨리기 때문에 복사한 규칙 집합이 자기 터널을 차단합니다.
route -n get default
ifconfig -l
scutil --nc list
첫 명령은 지금 이기는 인터페이스를 지목하고, 둘째는 커널이 아는 모든 장치를 나열하며, 셋째는 시스템이 시작할 수 있는 VPN 구성을 보여 줍니다. 그 답을 적어 두고, 클라이언트 자체 구성에서 서버 주소와 포트를 읽으십시오.
터널 경로를 중심으로 규칙 집합을 작성하십시오
아래 파일은 기본적으로 거부하고 다섯 가지를 다시 허용합니다—루프백, 터널 장치, 클라이언트에서 서버로 가는 경로, 터널이 생기기 전에 쓰는 해석기, 그리고 무선 링크를 쓸 만하게 유지하는 두 교환입니다. 인터페이스 이름과 서버 주소는 당신의 기계에서 나오므로 확인한 값으로 바꾸십시오. 터널 번호도 당신의 것과 맞지 않을 것입니다.
set skip on lo0
block all
pass out quick on utun0
# maintain this line when the server address changes
pass out quick on en1 inet proto udp to 203.0.113.10 port 1194
# only the resolver the client uses before the tunnel exists
pass out quick on en1 inet proto udp to 192.0.2.53 port 53
pass out quick on en1 inet proto udp from any port 68 to any port 67
pass out quick on en1 inet proto udp to 224.0.0.251 port 5353
DHCP 줄은 Mac이 주소를 갖기 전에 주소를 요청하기 때문에 있습니다—그래서 요청은 쓸 만한 출발지 주소 없이 포트 68에서 포트 67로 나갑니다. 멀티캐스트 줄은 무선 링크를 쓸 가치가 있는지 시스템이 판단하게 하며, 이것을 빼면 동작하는 네트워크에서도 연결 없음이라고 보고하는 기계가 됩니다. 끝점 줄은 OpenVPN 이 애초에 자기 서버에 닿게 하는 줄입니다—그것이 없으면 block all이 바깥 핸드셰이크를 떨어뜨리고 터널은 결코 올라오지 않습니다. 해석기 줄은 일반 DNS 허가보다 좁습니다—기계가 하는 모든 질의 대신 주소 하나와 포트 하나를 지목하기 때문입니다.
그 끝점과 해석기 예외가 반드시 있어야 하는 두 가지입니다—나머지는 모두 차단된 채로 남습니다. 클라이언트가 문자 그대로의 주소로 접속하면 해석기 줄을 빼고 끝점 줄을 유지하십시오. 서버 주소가 바뀌면 다음 연결 전에 그 줄을 갱신하거나, 클라이언트 자체 훅에서 pf 테이블을 채우고 대신 테이블을 일치시키십시오.
터널을 내리고 나서 재부팅하십시오
불러오기 전에 파싱하십시오—문법 오류는 마른 실행에서는 싸고 원격 세션에서는 비쌉니다. 그다음 파일을 불러오고, 필터가 꺼져 있었다면 켜고, 실제로 무엇이 효력이 있는지 되읽으십시오. 되읽기는 의식이 아닙니다—다른 앵커가 당신이 쓰지 않은 규칙을 더할 수 있으므로, 출력된 집합을 당신의 파일과 비교하십시오.
sudo pfctl -n -v -f /etc/pf.conf
sudo pfctl -f /etc/pf.conf
sudo pfctl -e
sudo pfctl -s rules
sudo pfctl -s Anchors
sudo pfctl -a <anchor> -s rules
sudo pfctl -s info
규칙을 불러온 상태에서 터널을 내리고 페이지를 불러와 보십시오. 보통 트래픽은 멈춰야 하고, 기계가 잠들었다 깨어난 뒤에도 멈춰 있어야 합니다——바로 그 전환에서 낡은 상태가 다시 스며들기 때문입니다. 다시 연결해 규칙 집합을 건드리지 않고 트래픽이 돌아오는지 확인하십시오. 터널을 내렸는데도 브라우저가 동작한다면 어떤 규칙이 생각보다 넓으며, 되읽기가 보통 그것을 지목합니다.
재부팅은 사람들이 건너뛰는 부분입니다. macOS는 부팅 때 /etc/pf.conf을 읽지만, 파일을 읽는 것과 필터를 켜는 것은 같지 않으므로 지금 동작하는 규칙 집합이 재시작 뒤에 비활성일 수 있습니다. 그 뒤에 sudo pfctl -s info을 실행하고 상태 줄이 필터를 활성으로 보고하는지 확인하십시오.
출구와 재시작 경로를 정직하게 유지하십시오
모든 것을 차단하는 규칙 집합은 원격으로 관리하는 기계에서 당신을 잠글 수도 있습니다. 가능하면 로컬 세션에서 편집하고, 이전 파일을 새 파일 옆에 두고, 필요해지기 전에 되돌리는 길을 알아 두십시오. 아래 명령은 필터를 끄고 보관한 사본을 다시 불러오며, 방금 끊은 터널을 통해서가 아니라 콘솔에서 실행할 순서입니다. 다섯 초의 되돌리기는 매번 영리한 규칙을 이깁니다.
sudo pfctl -d
sudo pfctl -f /etc/pf.conf.previous
sudo pfctl -s rules
지속성에는 pfctl -e을 실행하고 부팅 때 파일을 불러오는 launch daemon이 필요합니다. 다른 특권 작업처럼 다루십시오—절대 경로, 나중에 읽을 수 있는 로그, 그리고 물리적으로 닿을 수 있는 기계에서의 시험입니다. 조용히 실패하는 데몬은 기계를 무방비로, 평범해 보이게 남깁니다.
틈을 기록하십시오—먼저 자기 터널 장치를 만드는 두 번째 VPN 클라이언트입니다. 당신의 규칙은 터널 인터페이스 하나만 지목하므로 두 번째는 차단된 채로 남거나 나중에 추가된 넓은 규칙에 걸립니다. 테더링과 핫스폿 인터페이스는 가끔만 나타나며 같은 주석을 받을 자격이 있습니다. 그 틈 중 어느 것도 정책을 건너뛸 이유가 아닙니다—그것은 정책이 여전히 성립하는 조건입니다.