[LTE드론프로젝트] TCP Gender Changer (릴레이 서버)

category 분류없음 2019.03.05 15:53

안녕하세요? 도정진입니다.


음.. 4G 환경은 NAT 환경이라 이것을 극복하기 위해 OpenVPN 의 TAP 모드를 사용하거나 PPTP VPN 을 도입하는 방법이 있습니다. 그런데 드론 송출 관련으로 Gender Changer 라는 개념이 있어서 소개드립니다.


소개와 실측 테스트를 진행할 예정입니다.


기본적으로 리눅스 명령에 socat 이라는 명령이 있습니다. 기본적으로 xmltv.sock 에 epg 를 쏠때 사용한다고 알고 계실 텐데요. 저도 물론 그렇습니다. 이게 정확하게 무엇을 하는 것인지? 정확하게 지금도 모릅니다.


특정 TCP 포트와 UDP 포트에 대해서 socat 명령으로 릴레이를 할 수 있습니다. 이전에는 pwnat 이나 turnserver (coturn) 의 솔루션을 도입하려고 했습니다만, 이게 음.. 그렇게 만만하지가 않더라구요. pwnat 의 경우 이미 지금의 NAT 에서는 작동을 하지 않는 솔루션입니다.


일단 간단하게 socat 으로 TCP 릴레이를 해보겠습니다.


이와 관련하여 많은 외국 자료들을 서칭하였고 아래의 만족스러운 글을 찾아볼 수 있었습니다.


https://serverfault.com/questions/254855/socat-connect-connect-proxy-two-inbound-tcp-connections-to-expose-a-firewalled


http://www.dest-unreach.org/socat/doc/socat-gender.txt


원리는 이렇습니다.






1. socat 명령으로 릴레이 하기


기본적으로 아래와 같이 릴레이를 하시면 됩니다. 


공인아이피를 받는 서버에서 40000번 40001번 포트 2개를 열어줍니다. 40000번은 NAT 상태에 있는 서버랑 통신하는 용도, 40001번은 클라이언트가 연결할 포트입니다.


1. 서버측 (100.100.100.100)


socat tcp-listen:40000 tcp-listen:40001


2. NAT 상태의 서버 (TVHeadend TCP 포트)


socat 100.100.100.100:40000 localhost:9981


3. NAT 상태의 서버로 접근하려는 클라이언트

http://100.100.100.100:40001/


이런식으로 가능합니다.


socat 옵션에 fork 옵션과 reuseaddr 옵션이 있습니다. fork 옵션을 주게 되면 클라이언트가 연결을 끝더라도 연결이 지속됩니다. 계속 Child 프로세스를 만들기 때문입니다.


reuseaddr 의 경우 특정 프로그램들을 실행하고 종료할 때, 종료를 했음에도 불구하고 Address Already in use 라는 에러가 발생할 때가 있습니다. 이런 경우 TCP 컨넥션 단계중에 TIME_WAIT 에 걸려서 그렇습니다.


이 부분을 완화 하기 위해서 reuseaddr 옵션을 사용하는 것입니다.


이 옵션을 반영하면 아래와 같이 명령을 작성하면 됩니다.


socat tcp-listen:40000,fork,reuseaddr tcp-listen:4001


이외 관련하여 retry 옵션이 부여되어야 하고 udp 의 경우 tcp 가 아닌 udp 로 수행이 가능합니다.


한편으로는 프로그램 실행시 나오는 stdout 을 socat 으로 열어둘 수도 있습니다. 프로세스 실행 상태를 telnet 으로 확인이 가능합니다. 

(이러한 용도까지 사용되는 것인지 이제 알았네요.)





2. TCP Gender Changer (tgcd)


상기 명령 입력이 귀찮아 다른 분이 만들어 둔 소스가 있습니다.


https://github.com/kirgene/tgcd


상기 소스를 다운받아 컴파일 하여 실행해 보겠습니다. 두 곳 모두 있어야 합니다.


# 소스 받기

root@AOL-Debian:~# git clone https://github.com/kirgene/tgcd.git

Cloning into 'tgcd'...

remote: Enumerating objects: 46, done.

remote: Total 46 (delta 0), reused 0 (delta 0), pack-reused 46

Unpacking objects: 100% (46/46), done.

Checking connectivity... done.


# 소스 폴더로 이동

root@AOL-Debian:~# cd tgcd/


# 빌드 의존성 설치

root@AOL-Debian:~/tgcd# apt install autoconf build-essential

Reading package lists... Done

Building dependency tree        

Reading state information... Done

The following packages were automatically installed and are no longer required:

  g++-4.9 libstdc++-4.9-dev python-colorama python-distlib python-wheel

Use 'apt-get autoremove' to remove them.

The following extra packages will be installed:

  cpp cpp-8 g++ g++-8 gcc gcc-8 gcc-8-base libasan5 libatomic1 libcc1-0 libgcc-8-dev

  libgcc1 libgomp1 libisl19 libmpc3 libmpfr6 libstdc++-8-dev libstdc++6 libubsan1

Suggested packages:

  autoconf-archive gnu-standards autoconf-doc cpp-doc gcc-8-locales gcc-8-doc

  libstdc++6-8-dbg gcc-multilib flex bison gdb gcc-doc libgcc1-dbg libgomp1-dbg libitm1-dbg

  libatomic1-dbg libasan5-dbg liblsan0-dbg libtsan0-dbg libubsan1-dbg libmpx2-dbg

  libquadmath0-dbg libstdc++-8-doc

The following NEW packages will be installed:

  cpp-8 g++-8 gcc-8 libasan5 libcc1-0 libgcc-8-dev libisl19 libmpfr6 libstdc++-8-dev

  libubsan1

The following packages will be upgraded:

  autoconf build-essential cpp g++ gcc gcc-8-base libatomic1 libgcc1 libgomp1 libmpc3

  libstdc++6

11 upgraded, 10 newly installed, 0 to remove and 608 not upgraded.

Need to get 25.6 MB/26.4 MB of archives.

After this operation, 72.7 MB of additional disk space will be used.

Do you want to continue? [Y/n] 


# autoreconf 실행

root@AOL-Debian:~/tgcd# autoreconf -ivf
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force 
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force
autoreconf: running: /usr/bin/autoheader --force
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:13: installing './compile'
configure.ac:9: installing './install-sh'
configure.ac:9: installing './missing'
Makefile.am: installing './INSTALL'
Makefile.am: installing './depcomp'
autoreconf: Leaving directory `.'

# 환경 체크
root@AOL-Debian:~/tgcd# ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables... 
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking whether gcc understands -c and -o together... yes
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking for g++... g++
checking whether we are using the GNU C++ compiler... yes
checking whether g++ accepts -g... yes
checking dependency style of g++... gcc3
checking for ranlib... ranlib
checking for main in -lwrap... no
checking for main in -lnsl... yes
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for ANSI C header files... yes
checking for sys/wait.h that is POSIX.1 compatible... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking fcntl.h usability... yes
checking fcntl.h presence... yes
checking for fcntl.h... yes
checking netdb.h usability... yes
checking netdb.h presence... yes
checking for netdb.h... yes
checking arpa/inet.h usability... yes
checking arpa/inet.h presence... yes
checking for arpa/inet.h... yes
checking netinet/in.h usability... yes
checking netinet/in.h presence... yes
checking for netinet/in.h... yes
checking for stdlib.h... (cached) yes
checking for string.h... (cached) yes
checking sys/file.h usability... yes
checking sys/file.h presence... yes
checking for sys/file.h... yes
checking sys/ioctl.h usability... yes
checking sys/ioctl.h presence... yes
checking for sys/ioctl.h... yes
checking sys/param.h usability... yes
checking sys/param.h presence... yes
checking for sys/param.h... yes
checking sys/socket.h usability... yes
checking sys/socket.h presence... yes
checking for sys/socket.h... yes
checking sys/time.h usability... yes
checking sys/time.h presence... yes
checking for sys/time.h... yes
checking syslog.h usability... yes
checking syslog.h presence... yes
checking for syslog.h... yes
checking for unistd.h... (cached) yes
checking bits/sockaddr.h usability... yes
checking bits/sockaddr.h presence... yes
checking for bits/sockaddr.h... yes
checking asm/types.h usability... yes
checking asm/types.h presence... yes
checking for asm/types.h... yes
checking for an ANSI C-conforming const... yes
checking for pid_t... yes
checking for size_t... yes
checking whether time.h and sys/time.h may both be included... yes
checking vfork.h usability... no
checking vfork.h presence... no
checking for vfork.h... no
checking for fork... yes
checking for vfork... yes
checking for working fork... yes
checking for working vfork... (cached) yes
checking for stdlib.h... (cached) yes
checking for GNU libc compatible malloc... (cached) yes
checking whether gcc needs -traditional... no
checking sys/select.h usability... yes
checking sys/select.h presence... yes
checking for sys/select.h... yes
checking for sys/socket.h... (cached) yes
checking types of arguments for select... int,fd_set *,struct timeval *
checking whether setpgrp takes no argument... yes
checking return type of signal handlers... void
checking for strftime... yes
checking for wait3 that fills in rusage... yes
checking for gethostbyname... yes
checking for inet_ntoa... yes
checking for gettimeofday... yes
checking for memset... yes
checking for select... yes
checking for socket... yes
checking for strcasecmp... yes
checking for strdup... yes
checking for strerror... yes
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: executing depfiles commands

# 빌드 및 설치
root@AOL-Debian:~/tgcd# make && make install
make  all-am
make[1]: Entering directory '/root/tgcd'
gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT tgc.o -MD -MP -MF .deps/tgc.Tpo -c -o tgc.o tgc.c
mv -f .deps/tgc.Tpo .deps/tgc.Po
gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT tgcd.o -MD -MP -MF .deps/tgcd.Tpo -c -o tgcd.o tgcd.c
mv -f .deps/tgcd.Tpo .deps/tgcd.Po
gcc -DHAVE_CONFIG_H -I.     -g -O2 -MT utils.o -MD -MP -MF .deps/utils.Tpo -c -o utils.o utils.c
mv -f .deps/utils.Tpo .deps/utils.Po
gcc  -g -O2   -o tgcd tgc.o tgcd.o utils.o  -lnsl 
make[1]: Leaving directory '/root/tgcd'
make[1]: Entering directory '/root/tgcd'
 /bin/mkdir -p '/usr/local/bin'
  /usr/bin/install -c tgcd '/usr/local/bin'
 /bin/mkdir -p '/usr/local/share/man/man1'
 /usr/bin/install -c -m 644 tgcd.1 '/usr/local/share/man/man1'
make[1]: Leaving directory '/root/tgcd'
root@AOL-Debian:~/tgcd# 

# 바이너리 실행 확인
root@AOL-Debian:~/tgcd# tgcd
TCP Gender Changer, V1.0.2 Copyright (C) 2014 Faraz.V (faraz@fzv.ca)
Usage: tgcd { -C | -L | -F }  options ... 

Options are:

 ConnectConnect mode: tgcd -C -s host:port -c host:port [-i n ] [-k n ] [ common options ]
 ConnectConnect :
 -C, --ccnode     Become a CC (ConnectConnect) node.
 -s, --server host:port     The host and port of the actual server
 -c, --llhost host:port     The host and port of the ListenListen node.
 -i, --interval seconds     Time interval to periodically report to LL (default: 40s).
 -k, --key number     Poorman's encryption (0-255, default: 0, means no encryption)

 ListenListen mode: tgcd -L -p port  -q port [-t n] [-k n ] [ common options ...]
 -L, --llnode     Become a LL (ListenListen) node.
 -q, --llport number     The port to listen on for incomming connection from a CC node
 -p, --port number     The port to listen on for incomming actual client connection
 -t, --timeout seconds      Inactivity timeout during connection with CC node (default: 60s).
 -k, --key number     Poorman's encryption (0-255, default: 0, means no encryption)

 PortForwarder mode: tgcd -F -p port -s host:port [ common options ... ]
 -F, --lcnode     Become a ListenConnect node, i.e. just a simple port forwarder
 -p, --port  number     The port to listen on for incomming actual client connection
 -s, --server host:port     The host and port of the actual server or a LL node

Common options:
 -m, --method { f | s }     f: Fork  s: Select (default: s)
 -f, --filter filter     Optional argument to run filter on new connections, IP passed as argument
 -l, --log file     Write logs to file. (default:'')
 -g, --level number     Log level detail (default:0).
 -n, --nodaemon             Do not become daemon
 -h, --help     Display this.
 -v, --version     Display version number.





3. tgcd 테스트


1. 서버측


root@debian-4350:~/tgcd# tgcd -L -p 40000 -q 40001


root@debian-4350:~/tgcd# netstat -nlp | grep tgcd

tcp        0      0 0.0.0.0:40000           0.0.0.0:*               LISTEN      97416/tgcd    

tcp        0      0 0.0.0.0:40001           0.0.0.0:*               LISTEN      97416/tgcd


2. NAT 환경 서버측










댓글을 달아 주세요