VPN 연결 나눠쓰기

Featured image

예전에도 이것에 대해서 정리한 적이 있는데 또 금새 잊게 될 것 같아서 다시 적어본다.

  1. VPN

VPN을 하려면 먼저 터널링이 되어야 한다. 터널링은 쉽게 말해서 원래 패킷에 껍데기를 씌워서 다른 네트워크에서 유통시킬 패킷들을 돌리는 것을 말한다.

네트워크 A에 속한 호스트 1이 있고 네트워크 B에 속한 호스트 2가 있다고 하자. 여기서 네트워크라고 하는 것은 인터넷이 아닌 로컬 네트워크를 의미하고 서로 다른 주소 대역을 사용한다고 본다. 호스트 1과 호스트 2는 인터넷을 통해서 접속할 수 있다고 하면, 실제로 2개의 네트워크 디바이스를 가지고 있어야 한다. 왜? 로컬 네트워크와 외부 네트워크(인터넷)의 주소 대역이 다르기 때문이다.

네트워크 A <==로컬넷==> 호스트 1 <===인터넷===> 호스트 2 <==로컬넷==> 네트워크 B

그러나 실제로 이렇게 되어있지 않다. 왜냐면 우리가 라우터라는 것을 가지고 있고 대부분 주소속이기 (ip masquerading)이란 것을 하고 있다는 것을 잘 모를 뿐이지 우린 늘 IP 주소를 늘상 바꿔치기하고 캡슐링하고 하는 일을 하고 있다.

즉, 실상은 다음과 같다.

호스트 1 <==로컬넷 A==> 라우터/스위치 <===인터넷===> 라우터/스위치 <==로컬넷 B=> 호스트 2

그러니까 라우터/스위치가 스스로 여러 개의 네트워크 카드를 가지고 있어서 본래의 라우팅/스위치 가능도 하면서 인터넷 주소와 로컬 넷 주소를 바꿔치는 기능도 하고 있다.

다시 말해 내가 집에서 192.168.0.10의 주소를 가지고 패킷을 주고 받더라도 인터넷 상에서 보여지는 주소는 ISP가 가지고 있는 주소 중에 하나로 보이게 되는 데 그것은 전부 다 이런 주소 바꿔치기 기능 때문에 가능한 것이다.

VPN이란 것은 로컬넷 A에서 로컬넷 B로 연결하는 것이라고 보면 된다. VPN을 쓰지 않고도 위 그림대로 실제로 통신이 이루어지고 있지 않냐 할 수 있을텐데, 그것은 로컬넷 A와 로컬넷 B에서 인터넷을 통해서 공개적으로 포트를 열어두고 포트 포워딩(특정 tcp 포트만 연결하게 하는 방법)이라든가 터널링(특정 네트웍에서 특정 네트워크로의 트래픽 모두를 연결시키는 방법)이 가능하도록 router를 설정했기 때문이다.

이렇게 하면 보안상의 문제가 생겨버리기 때문에 VPN이란 것을 쓴다. P라는 것이 private(=not public)이란 것을 뜻한다.

예를 들어 로컬넷 B가 호스트 2를 이용해서 VPN 서비스를 하겠다고 하면 라우터 (게이트웨이)에서 포트 포워딩을 통해서 호스트 2의 특정포트를 연결시킨다. 그러면 VPN을 사용하려는 호스트 1은 라우터의 특정 주소:포트 번호로 접속하여 호스트 2로 접속한다. 그러면 호스트 2에서는 터널링 디바이스를 만들고 호스트 1에서도 터널링 디바이스를 만들어서 양방향으로 패킷 포워딩이 가능하도록 한다. 로컬넷 B의 라우터는 호스트 1로 향하는 모든 패킷들은 호스트 2로 가게끔 라우팅 테이블을 설정한다. 또 호스트 2는 스스로 패킷 포워딩이 가능해야 한다. 무슨 말이냐면 그 자체가 패킷 포워딩을 통해서 받은 패킷의 껍데기를 제거한 후 로컬넷 B로 전달시킬 수 있어야 된단 말이다. 그러면 호스트 1은 호스트 2를 포함한 로컬넷 B에 있는 호스트들과 패킷을 주고 받을 수 있게 된다.

이게 VPN이다. 실제 로컬넷A와 B사이에 직접 wire를 연결한 것이 아니니 virtual이고 인터넷에 대놓고 tunneling을 한 것이 아니니 private인 것이다.

  1. VPN 연결을 나눠쓰기

이 상태에서 로컬넷 A에 있는 다른 호스트들이 호스트 1의 VPN연결을 나눠쓰려면 호스트 1도 호스트 2가 하는 것처럼 할 수 있게 하면 된다. 즉, 로컬넷 A의 라우터가 로컬넷 B의 주소대역의 패킷들을 무조건 호스트 1로 보내지도록 라우팅 테이블을 설정해야 하고 호스트 1이 스스로 패킷 포워딩을 하도록 해서 로컬넷 B에서 온 패킷들을 로컬넷 A에 유동시키도록 해야 한다.

그러나, 보안을 따지는 회사들은 자체적으로 VPN 소프트웨어를 따로 두고 있고 이 소프트웨어도 특정 조건 (인증서 등등)이 되어야만 실행시킬 수 있게 해놓았음은 물론 해당 호스트의 인터넷 트래픽을 통제해서 사실상 해당 호스트만 VPN을 쓸 수 있도록 해놓았다. 일단 위의 조건들을 만족시키려면 보안소프트웨어를 완전히 무력화해놓고 관리자 권한을 가져야 할 수 있는데 이런 걸 되게 해놓았을리가 없단 말이다.

그러면 어떻게 해야 하나?

일단 보안소프트웨어는 ssh에 대해서 관대한 입장을 가지고 있는 반면 ssh는 매우 다양한 기능을 가지고 있다. ssh 기능 중 하나가 SOCKS proxy를 할 수 있다는 것이다.

이게 무슨 소리냐면, 이를테면 내가 인터넷 서비스 하나를 뚫기 위해서 게이트웨이에서 포트 포워딩을 했다고 하면 이것은 포트 하나의 트래픽을 포워딩한 것에 불과하다. 그런데 SOCKS로 패킷을 프락시 한다고 하면 실제로는 포트 하나로 데이터를 주고 받지만, 양쪽의 특정 주소 대역을 사용하는 트래픽 전체를 포워딩하는 것이다. 그러니까 ssh가 SOCKS를 이용한 터널을 하나 뚤어주는 것이다. ssh 자체적으로 암호화가 되니까 귀찮게 VPN 소프트웨어 깔고 말고 할게 없이 ssh만 잘 쓰면 되는 것이다.

여기에 더더욱 재미난 것은 리버스 포트 포워딩/리버스 터널링 기능이 있다. 이것은 분명히 보안 소프트웨어가 잡아내야 할 보안구멍인데 잡아내는 소프트웨어는 보지 못했다.

리버스 포트 포워딩/리버스 터널링이란 것은 내가 특정 호스트에 접속해서 해당 호스트의 로컬 포트/로컬 네트워크 디바이스를 만들게 하여 해당 통로로 패킷을 유통시킬 수 있게 하는 것이다. 다시 말해 특정 호스트가 내 호스트로 접속해서 패킷을 요구하고 받아가야 맞는데, 반대 방향으로 내 호스트가 그쪽으로 접속해서 포트나 터널을 뚫어주는 것이다. 보안 소프트웨어가 바라보는 입장에서는 ssh 접속을 한 것처럼만 보일 뿐 리버스 포워딩을 하고 있는지 뭔지는 잘 모른다.

일단 ssh로 SOCKS 리버스 터널링을 하게 하려면 해당 호스트에 터널링 디바이스를 하나 만들어야 된다. 그리고 그 터널링 디바이스로 SOCKS proxy를 통해 패킷을 흘릴 수 있도록 tun2socks라는 기능을 사용하는데 badvpn이란 툴로 이걸 가능하게 할 수 있다. 즉, ssh 연결 하나만 있으면 특정 로컬넷에 있는 호스트 전체가 VPN 연결을 공유할 수 있다. 그 다음 내부 라우팅 테이블을 특정 주소 대역에 대한 연결은 모두 터널링 디바이스로 연결되도록 설정한다.

그러나 이것은 단방향이기 때문에, 반대방향으로도 터널링을 해주어야 한다. 일단 리버스 터널링을 개시하자마자 상대방 호스트에서 마찬가지로 리버스 터널링을 뚫어준다. 그 다음 로컬 라우터에서 특정 주소 대역의 패킷은 모두 해당 호스트로 전달되도록 조정한다.

  1. 요약하기

이 과정이 매우 번거롭기 때문에 중간에 나가 떨어질 수 있다. 고작 VPN 연결 하나 공유하자고 이런 짓까지 해야 하나 할 수도 있다. 구닥다리 랩탑 한대를 가지고 많은 일을 하려면 이 방법 말곤 방법이 없다.

1) 터널링하려는 호스트에 터널링 디바이스 만들기 2) kernel에 ip packet forwarding이 가능하도록 설정함. 3) routing table에 해당 주소 대역–>터널링 디바이스에 대한 내용 추가하기 4) badvpn 설정하기 (로컬주소:특정포트로 들어온 socks packet을 tunnel device로 연결 하기) 5) VPN 접속이 가능한 PC에서 sshd를 띄우고 ssh를 이용해서 터널링 호스트의 특정포트로 SOCKS proxy reverse tunneling연결을 설정한다. 동시에 해당 호스트에서 동일한 리버스 터널링을 할 수 있도록 ssh를 실행시킨다. 6) 4의 결과로 터널링 호스트의 내부에 SOCKS proxy 포트가 열리고 이 포트로 tun2sock 기능을 실행해서 해당 호스트의 터널링 디바이스로 가는 패킷을 모두 socks 패킷으로 바꿔서 VPN PC로 보낼 수 있다. 해당 PC는 ssh가 SOCKS 패킷으로 온 것을 일반 패킷으로 바꿔서 VPN 연결을 통해서 전달시킨다. 또, 터널링 호스트에서 설정한 reverse socks proxy 설정에 의해서 VPN PC에서 수신된 패킷들은 해당 PC의 로컬 포트를 통해서 forwarding할 수 있게 되어 양방향 터널이 생기게 된다. 7) 로컬 라우터의 라우팅 테이블에 해당 주소 대역의 패킷은 모두 터널링 호스트로 가게끔 내용을 추가한다.

많은 설명을 생략했는데 하다보면 이해할 수 있게 된다. 또 이게 막상 실행되게 되면 모든 과정을 스크립트로 만들어서 하게 되면 어떻게 만들었는지 금방 잊게 되는데 혹시나 시스템이 날아가게 되거나 갑자기 교체하게 되는 경우를 대비해서 모두 백업해놓도록 하자. 모두 망각한 상태에서 새로 셋업하려면 제법 시간이 들어간다.