No Rules Rules

WSL 포트 포워딩 (feat. port forwarding, TCP만 지원함) 본문

생활/업무

WSL 포트 포워딩 (feat. port forwarding, TCP만 지원함)

개발하는 완두콩 2022. 7. 20. 14:04
728x90
반응형

팀에서 수행했던 과제중 최초로 WSL을 사용하고 있습니다. 왜 다들 VM을 사용하지? 라는 단순한 의문에서 시작된 저의 결정입니다.

 
WSL이 뭐지?

리눅스용 윈도우 하위 시스템(Windows Subsystem for Linux, WSL)을 의미합니다.
알고 있는 내용을 적어봤자 위키보다 잘 알순 없으니 링크를 걸께요.

 

 

 

리눅스용 윈도우 하위 시스템 - 위키백과, 우리 모두의 백과사전

리눅스용 윈도우 하위 시스템 윈도우에서 네이티브로 리눅스 실행 파일을 실행하기 위한 호환성 계층

ko.m.wikipedia.org


VM에 비해 빠릿빠릿한 속도를 보여준다는게 가장 큰 장점. 메모리 또한 충분하다는게 몸소 느껴집니다. (SSH를 이용한 Visual Studio간 디버깅도 상당히 만족스럽습니다.)

 

그런데 오늘 문제가 하나 생겼어요.

내 PC(즉, 로컬PC)와 WSL간 TCP/UDP 통신은 아무런 문제가 없는데, 다른 사람들의 PC(즉, 외부PC)와 WSL간 TCP/UDP 통신은 안되는거예요. 찾아봤더니 진짜 안되는거였어요. (나만 안되는게 아니라서 다행이예요... 응?)

 

물론 검색을 해보면 netsh를 이용해서 portproxy add를 하면 된다고 해요.

아무리 해도 안되요. 뭐 떄문일까요?

방법을 찾다보니 도저히 답이 안나와서 원인을 알아보았어요.

세상에. microsoft의 설명서에 나와있어요. (WSL은 리눅스지만 마소에서 제공하는 서비스예요.)

맞아요. TCP만 현재 지원됩니다. (WSL2 기준이예요.)

 

UDP만 테스트하면서 왜 안돼!!! 라고 했는데, TCP로 외부PC와 WSL간 통신을 해보니 잘되네요.

하지만 저는 UDP통신도 필요해요. 어떻게 해야할까 계속 고민하다 netcat을 사용하기로 했어요.


 

누군가는 WSL에서 포트 포워딩을 하려면 어떻게 해야하나? 가 궁금해서 오셨을꺼예요.

결론부터 말씀드리면 현재 나와있는 WSL2는 TCP만 포트 포워딩을 지원해줘요.

TCP통신만 외부PC와 WSL간 필요하다면 이렇게 하시면 됩니다.

 

일단 방법을 말씀드리기 전에 개념을 잡고 가봐요.

WSL의 아이피가 192.168.10.20 이라고 하고, 10000번의 TCP 포트로 데이터를 받고 싶어요.

그리고 로컬 PC의 아이피가 192.168.10.30 이라고 해볼께요.

 

우리의 원래 목적은 외부PC에서 192.168.10.20의 주소와 10000번의 TCP 포트로 데이터를 전송하는 것이예요. (도착지가 WSL이니까요.)

하지만 이건 죽었다 깨어나도 안됩니다. 왜냐면 WSL와 로컬PC는 이더넷 어댑터를 통해 연결이 되어 있는데, 이건 외부와 연결된 통로가 아니예요. 오로지 로컬PC와의 연결을 위해서만 사용된답니다.

그래서 포트 포워딩을 하려고 해요. 포트 포워딩은 외부PC에서 로컬PC인 192.168.10.30 으로 TCP 데이터를 보내주는거예요. TCP 데이터를 보내고 받을때는 TCP 포트가 필요하죠? 그 포트를 10000번이라고 한다면, 외부PC는 로컬PC인 192.168.10.30 주소의 10000번 TCP 포트로 보내는거예요. 그럼 로컬PC가 TCP 데이터를 WSL인 192.168.10.20 아이피의 10000번 TCP 포트로 데이터를 보내주는거죠. 중계기같은 역할이라고 보시면 됩니다.

그림으로 보면 다음과 같습니다.

반응형

이렇게 로컬PC에 포트 포워딩을 해두면, 10000번 TCP Port로 수신된 정보를 WSL의 10000번 TCP Port로 송신해주는 기능입니다.

별거 아니죠?

로컬PC가 데이터를 받고, 그때의 TCP 포트가 포워딩된 포트라면

WSL로 스르륵 넘겨주는거예요.

 

 

어떤 포스팅이 원조인지 모를만큼 동일한 예제가 퍼져있으니, 그대로를 가져왔어요.

대신 한줄한줄 설명 드릴께요.

아래 내용은 wsl_port_forwarding.ps1 이라는 파일로 저장하시구요.

Windows PowerShell을 관리자로 실행하신 뒤에 실행시켜주면 됩니다.

 

#아래는 ifconfig eth0 이라고 리눅스에서 실행했을때
#첫 단어가 inet으로 시작하는 라인만을 출력하는거예요
#만약 로컬PC->WSL 로 보낼 아이피가 eth0이 아니라면 수정하면 되요.
$remote_ip = bash.exe -c "ifconfig eth0 | grep 'inet '"

#아래는 위 remote_ip 중에서 xxx.xxx.xxx.xxx 형식을 가지는 부분이 있는지를 보는거예요
$found = $remote_ip -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( $found )
{
  #있으면 그중 첫번째 문자열을 가지고 옵니다.
  #즉, 로컬PC->WSL 로 보낼 아이피가 remote_ip에 남게 됩니다.
  $remote_ip = $matches[0];
  echo "remote ip is $remote_ip";
} else{
  echo "The Script Exited, the ip address of WSL 2 cannot be found";
  exit;
}

#포워딩할 포트를 아래에 넣어주시면 되요.
#아래는 10000번, 10001번 TCP 포트를 포워딩 포트로 정했어요.
$ports=@(10000, 10001);

#특정 외부 PC에서만 받겠다고 지정할 수 있어요.
#0.0.0.0 으로 설정하면 제한을 두지 않아요.
$addr='0.0.0.0';

#이전에 포워딩했던 정보가 있다면 리셋해주는 구문이예요.
Invoke-Expression "netsh interface portproxy reset";

#포워딩할 포트 개수만큼 반복해요.
#포워딩 포트와 아이피를 listen하도록 하고, 포워딩 포트와 WSL 아이피를 connect해요.
for( $i = 0; $i -lt $ports.length; $i++ )
{
  $port = $ports[$i];
  Invoke-Expression "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  Invoke-Expression "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}
 

여기서 알 수 있는건 바로 이거예요.

 

로컬 PC의 포워딩할 TCP 포트와 WSL의 TCP 포트가 같을 필요는 없다!

 

위의 코드는 말씀 드렸지만 여기저기 퍼져있는 코드예요.

portproxy add 에서 listen 정보가 외부 PC에 대한 정보 (포트는 외부 PC -> 로컬 PC 의 포트, 아이피는 외부 PC의 아이피)

connect 정보가 WSL에 대한 정보 (포트는 로컬 PC -> WSL 의 포트, 아이피는 WSL의 아이피)

이것만 기억하면 됩니다.

 

다음은 netcat에 대해서 얘기하겠습니다.

 

728x90
반응형
Comments