터널을 멈추지 않고 OpenVPN 클라이언트 하나를 LAN에서 차단하기
클라이언트의 터널 주소를 인증서에 고정하고, FORWARD 맨 앞에서 LAN 트래픽을 버린 뒤, IPv6와 추적 세션, 재부팅 후 유지를 확인합니다.
OpenVPN 서버에서 클라이언트 하나만 LAN 접근을 잃고 나머지 터널은 모두 살아 있어야 합니다. 이걸 검색하면 보통 데몬이 할 수 없다는 답이 가장 위에 나오는데, 절반만 맞습니다. OpenVPN에는 클라이언트별 방화벽이 없지만, 터널을 종료하는 호스트는 이미 패킷을 필터링합니다. 중요한 결정은 두 가지, 차단할 신원과 규칙의 위치입니다. 이 둘을 맞추면 변경은 시험하고 되돌릴 수 있는 한 줄이 됩니다.
규칙을 쓰기 전에 클라이언트를 고정하십시오
OpenVPN은 풀에서 터널 주소를 임대하므로 10.8.0.6은 사람이 아니라 좌석입니다. 세션이 끝나면 임대가 반납되고 다음 연결에 넘어갈 수 있어, 그 주소에 대해 쓴 규칙은 사용자가 아니라 좌석을 따라갑니다. 그래서 먼저 무엇을 막는지 정하십시오. 짧은 실험용 주소인지, 내보내 두고 싶은 사람의 인증서인지.
주소를 인증서에 묶으려면 client-config-dir이 가리키는 디렉터리에 파일을 만들고 파일 이름을 인증서의 common name과 똑같이 하십시오. 안에 지시문 하나를 넣으십시오. ifconfig-push 10.8.0.6 255.255.255.0, 그러면 그 클라이언트는 다시 연결해도 같은 터널 주소를 유지합니다. 적용되려면 두 설정이 있어야 합니다. client-config-dir가 서버 설정에 선언되어야 하고, 밀어 넣는 주소가 서버가 라우팅할 수 있는 서브넷에 있어야 합니다. 하나라도 빠지면 파일은 오류 없이 무시되고, 다음 방화벽 시험이 오해를 부릅니다.
임시 차단은 풀 주소를 써도 되지만, 그 시점에 어느 세션이 그 주소를 쥐고 있었는지 티켓에 기록해야 합니다.
순서가 드롭의 실행을 결정합니다
터널과 LAN 사이를 전달하는 Linux 게이트웨이에서는 패킷이 FORWARD 체인을 지납니다. 아래 명령을 문장으로 읽으십시오. FORWARD 맨 앞에 삽입하고, tun0에서 들어오는, 그 호스트 하나에서 온, LAN 서브넷으로 향하는 트래픽을 일치시켜 버립니다.
iptables -I FORWARD -i tun0 -s 10.8.0.6/32 -d 192.168.1.0/24 -j DROP규칙을 돌게 하는 것은 -I입니다. -A로 덧붙이면 터널 서브넷에 대한 넓은 허용 아래로 내려가 패킷을 보지 못합니다. 위치는 iptables -vnL FORWARD --line-numbers로 확인하고 카운터도 읽으십시오. 맨 위 드롭이 아무것도 세지 않는다면 트래픽이 다른 경로로 들어오고 있는 것입니다.
게이트웨이 자체의 LAN 주소는 다른 경로입니다. 상자 자체로 보낸 패킷은 INPUT로 가고 FORWARD를 지나지 않으므로, 클라이언트가 LAN 호스트는 잃어도 공유기 관리 페이지는 열 수 있습니다. 그것이 문제라면 대응하는 INPUT 규칙을 더하십시오.
필터가 볼 수 없는 것
필터링은 패킷을 평가할 때 일어나므로, 이미 성립한 TCP 세션은 닫히거나 재설정될 때까지 계속됩니다. 차단이 즉시 효과를 내야 한다면 규칙을 넣은 뒤 conntrack -D -s 10.8.0.6로 그 출발지의 추적 흐름을 지우십시오. 몇 초의 겹침이 괜찮다면 그 선택을 암묵적으로 두지 말고 기록하십시오. 어느 쪽이든 다음 사람은 이 규칙이 살아 있는 트래픽을 끊는지 새 연결만 막는지 알아야 합니다.
피어 사이 트래픽은 호스트 방화벽을 전혀 거치지 않습니다. client-to-client가 켜져 있으면 OpenVPN이 그 패킷을 데몬 안에서 전달하므로 FORWARD도 INPUT도 보지 못합니다. 고칠 방법은 client-to-client를 끄거나 피어가 서로 닿을 수 있음을 받아들이는 것뿐입니다. iptables 규칙은 그 트래픽을 보지 못합니다.
IPv6, 펌웨어, 재부팅 후 유지
IPv4 규칙은 IPv6에 대해 아무 말도 하지 않습니다. 터널과 LAN이 두 체계를 모두 나른다면 같은 규칙이 ip6tables에 있어야 하고, 또는 그 호스트의 정책을 가진 nftables 규칙 집합에 있어야 합니다. 공유기 펌웨어는 netfilter를 자체 추상화 뒤에 숨기는 일이 많아, 포럼에서 복사한 문법과 테이블 이름이 맞지 않을 수 있습니다.
OpenWrt에서 문서화된 길은 방화벽 설정 항목이지 손으로 쓴 iptables 줄이 아니며, 손으로 쓴 줄은 방화벽을 다시 불러올 때 사라질 수 있습니다. 다른 배포판은 netfilter-persistent, 부팅 유닛, 벤더 저장소로 규칙을 복원하며 이런 방식은 서로 바꿀 수 없습니다. 고른 방식을 재부팅으로 증명하십시오. 다시 불러오기는 다른 경로를 연습할 뿐입니다.
경로별로 확인하고 깔끔하게 되돌리십시오
경로를 하나씩 시험하십시오. 하나가 성공하면 나머지가 가려집니다. 차단된 클라이언트는 터널로 인터넷에는 닿아야 하고 LAN 호스트에는 실패해야 하며, 두 번째 클라이언트는 같은 호스트에 닿아야 하고, 게이트웨이 주소와 피어 경로는 각각 따로 관찰해야 합니다. 결과를 규칙 옆에 적어 다음 변경의 기준으로 삼으십시오. 아래 표가 티켓에 남길 만한 집합입니다.
| 경로 | 규칙이 있을 때 기대 | 실패할 때 |
|---|---|---|
| 차단된 클라이언트에서 LAN 호스트로 | 응답 없음 | 규칙이 허용 아래에 있거나 출발지가 일치하지 않음 |
| 차단된 클라이언트에서 인터넷으로 | tun0로 동작 | 규칙이 너무 넓고 목적지 일치가 없음 |
| 두 번째 클라이언트에서 같은 LAN 호스트로 | 동작 | 규칙이 의도한 호스트보다 많이 일치함 |
| 차단된 클라이언트에서 게이트웨이 LAN 주소로 | 대응하는 INPUT 규칙이 있어야만 차단됨 | INPUT 규칙 없음 |
| 차단된 클라이언트에서 피어 터널 주소로 | 여전히 동작 | client-to-client가 켜져 있고 방화벽 범위 밖임 |
되돌리기는 사양에 따른 삭제이지 플러시가 아닙니다. iptables -D FORWARD -i tun0 -s 10.8.0.6/32 -d 192.168.1.0/24 -j DROP는 바로 그 항목만 지우고 체인의 나머지는 그대로 둡니다. 부팅 시 규칙을 복원하는 파일에서도 같은 줄을 지우고 다시 불러온 뒤, 클라이언트가 다시 LAN 호스트에 닿는지 확인하십시오. FORWARD를 플러시하면 쓰지 않은 규칙까지 되돌려져 롤백이 두 번째 사고가 됩니다.
티켓을 닫기 전에 세 가지를 확인하십시오. 고정한 주소가 인증서와 일치하는지, 규칙이 허용 위에 있고 카운터가 영이 아닌지, 지속 파일에 시험한 것과 같은 규칙이 있는지. 하나라도 빠지면 그 차단은 셸 세션 안의 착각입니다.