라즈베리 파이 제로를 인터넷에 연결하기

이번 프로젝트의 목적은 학교 컴퓨터에 로그인하기 위해 VPN에 먼저 접속해서 포트 포워딩을 설정한 다음 VPN을 끊는 과정을 매주 반복해야 하는 번거로움을 해결하는 것이다. 현재도 VPN으로 학교 컴퓨터에 접속이 가능하지만 VPN에 제한 시간이 있다. 그래서 PuTTY를 이용해서 포트 포워딩을 해 둔 다음 VPN을 끊어 버린다. 즉, VPN 접속, RDP 로그인, PuTTY로 집 서버로 로그인하는 과정을 매주 또는 네트워크가 끊어질 때마다 반복해야 한다. 지금 생각하고 있는 방법은 학교 컴퓨터의 USB 포트에 라즈베리 파이 제로를 설치해서 인터넷을 공유한 다음 파이에서 집 서버로 포트 포워딩을 설정해 두는 것이다. 그러면 집에서 파이를 거쳐서 학교 컴퓨터로 RDP 로그인이 가능하지 않을까?

우선, 보안을 위해 비밀번호를 저장해야 하는 와이파이는 쓸 수 없다. 그래서 라즈베리 파이 제로 W 대신 라즈베리 파이 제로에 크기가 작은 1GB SD 카드를 꽂아서 설정하기로 했다.

1   파이코어 설치하기

SD 카드의 용량이 작기 때문에 타이니 코어 리눅스를 설치한다. 파이 제로 W와는 다르게 와이파이를 설정할 필요가 없다.

여기서는 처음 부팅하기 전에 파일 시스템을 준비해 보도록 하자.

piCore-11.0.zip 파일을 다음과 같이 SD 카드로 써 준다.

su - # 아직 파이가 아니고 랩탑이다.

unzip -p piCore-11.0.zip piCore-11.0.img | dd of=/dev/mmcblk0 bs=4M conv=fsync status=progress

# SD 카드를 뺐다가 다시 꽂는다.

fdisk /dev/mmcblk0 # 2번 파티션의 크기를 확장한다.
# p 명령으로 현재 섹터를 확인한다.
# d 명령으로 2번 파티션을 삭제한다.
# n 명령으로 2번 파티션을 다시 생성한다.
#   이 때 p 명령에서 확인한 시작 섹터에서 시작하고 마지막 섹터까기 파티션을 확정한다.
# w 명령으로 파티션을 저정하고 빠져 나온다.

e2fsck -f /dev/mmcblk0p2 # resize2fs를 먼저 실행하면 이 명령을 실행하라고 한다.
                         # 의외로 고칠 게 좀 있다.

resize2fs /dev/mmcblk0p2 # 파일 시스템의 크기도 확장한다.

2   dwc2 설정하기

파이를 이더넷 디바이스로 인식시키기 위해서는 dwc2 디바이스 트리 오버레이를 설정해야 한다.

mount /dev/mmcblk0p1 /mnt
echo dtoverlay=dwc2 >> /mnt/config.txt
umount /mnt

3   g_ether를 위한 확장 생성 및 설치하기

USB를 통해서 인터넷을 설정하기 위해서는 g_ether 모듈이 필요하다. 그런데 이 모듈은 패키지화되어 있지 않다. 그래서 modules.tar.gz내려받아서 직접 확장을 만들어야 된다.

cd /tmp
tar xvf modules.tar.gz
mkdir -p usb-gadget/usr/local/lib/modules/4.19.81-piCore/kernel/drivers/usb
cd modules/lib/modules/4.19.81-piCore/kernel/drivers/usb
cp -a dwc2 gadget /tmp/usb-gadget/usr/local/lib/modules/4.19.81-piCore/kernel/drivers/usb
cd /tmp
rm -rf modules

mksquashfs usb-gadget usb-gadget-4.19.81-piCore.tcz
rm -rf usb-gadget

mount /dev/mmcblk0p2 /mnt
cp usb-gadget-4.19.81-piCore.tcz /mnt/tce/optional
chown 1001.50 /mnt/tce/optional/usb-gadget-4.19.81-piCore.tcz

cat<<'EOT'>> /mnt/tce/onboot.lst
usb-gadget-4.19.81-piCore.tcz
EOT

4   sshd를 위한 확장 설치하기

이 파이는 파워 포트가 아닌 USB 포트를 써서 컴퓨터에 연결하기 때문에 키보드를 연결할 수 없다. 그래서 헤드리스(headless) 파이가 될 것이다. 테스트를 위해서 파워 포트로 전원을 넣고 키보드를 연결한 채로 sshd가 실행되는지 확인해 봤다. 잘 돌아갔다. 그런데 키보드를 빼고 부팅하니 sshd에서 멈춰 버렸다. 이상하게 키보드를 연결하고 엔터를 치니까 sshd가 계속 실행되었다. 이거 아무래도 어디선가 읽은 듯한 느낌이었다. 헤드리스 서버의 엔트로피가 너무 낮으면 문제가 생길 수 있다는 글을 본 적이 있다. 파이에는 하드웨어 난수 발생기가 있는데 rng-tools를 설치해야 사용할 수 있다. get_picore_pkg를 이용해서 이 확장을 설치하자.

cd /mnt/tce/optional
get_picore_pkg rng-tools

5   mydata.tgz 준비하기

이제 시스템 파일과 HOME 디렉토리를 준비하자. usb0 인터페이스의 고정 IP 주소를 192.168.137.2로 설정한다. 호스트 컴퓨터의 usb0 인터페이스는 192.168.137.1로 설정한다. 192.168.137.1은 윈도에서 인터넷을 공유하면 USB 인터페이스에 자동으로 설정하는 IP 주소이다.

mkdir /tmp/mydata
cd /tmp/mydata

tar xvfz /mnt/tce/mydata.tgz

vi opt/bootlocal.sh # 다음과 같이 수정한다.
-----
#!/bin/sh

# Start serial terminal
/usr/sbin/startserialtty &

# Set CPU frequency governor to ondemand (default is performance)
echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

# Load modules
/sbin/modprobe i2c-dev

# Start openssh daemon
/usr/local/sbin/rngd # by hcho
/usr/local/etc/init.d/openssh start

# ------ Put other system startup commands below this line

# by hcho
for i in /home/tc/etc/rc.d/rc.*; do
        if [ -x $i ]; then
                $i start
        fi
done
-----

mkdir -p home/tc/etc/rc.d

# dtoverlay=dwc2와 함께 파이를 USB 이더넷 디바이스로 인식하게 하는 모듈을 읽어 들인다.
cat<<'EOT'> home/tc/etc/rc.d/rc.g_ether
#!/bin/sh
modprobe g_ether
EOT
chmod a+x home/tc/etc/rc.d/rc.g_ether

# 파이의 IP 주소는 192.168.137.2이고 호스트의 IP 주소는 192.168.137.1이다.
cat<<'EOT'> home/tc/etc/rc.d/rc.usb0
#!/bin/sh
ifconfig usb0 192.168.137.2
route add default gw 192.168.137.1
echo nameserver 192.168.137.1 > /etc/resolv.conf
EOT
chmod a+x home/tc/etc/rc.d/rc.usb0

chown -R 1001.50 home/tc/etc

tar cvfz /mnt/tce/mydata.tgz .

umount /mnt

cd /tmp
rm -rf mydata

6   고정 IP 주소로 파이에 접속하기

이제 SD 카드를 파이에 꽂고 USB 케이블을 PWR가 아닌 USB에 연결하고 호스트 컴퓨터에도 연결한다. 호스트의 IP 주소를 앞서 설명한 192.168.137.1로 설정한다. 파이는 ssh tc@192.168.137.2로 접속이 가능하다. 파이 내에서도 인터넷이 된다.

6.1   리눅스 호스트

su - # 호스트 컴퓨터의 root로 로그인한다.

# 파이의 부팅이 끝나면 Netchip Technology, Inc. Linux-USB Ethernet/RNDIS Gadget라는 USB 디바이스가 생성된다.
lsusb # 위의 디바이스가 보일 때까지 lsusb를 반복 실행한다.

# NetworkManager가 usb0의 연결을 끊어 버리는 것을 방지한다.
nmcli dev set usb0 managed no

# 호스트 USB 인터페이스의 IP 주소를 설정한다.
ifconfig usb0 192.168.137.1

# IP 포워딩을 활성화한다.
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

6.2   윈도 호스트

만약, RNDIS 드라이버가 설치되어 있지 않아서 파이가 시리얼 디바이스로 인식될 경우 여기에 있는 RNDIS 드라이버를 설치하면 된다. 디바이스 매니저를 열고 파이의 시리얼 포트 디바이스에서 업데이트 드라이브를 하면 된다.

  • Control Panel ⇒
  • Network and Sharing Center ⇒
  • 주 네트워크의 Properties ⇒
  • Sharing ⇒
  • Allow other network users to connect through this computer’s Internet connection 활성화 ⇒
  • Home networking connection ⇒
  • USB 이더넷 네트워크 선택

그런데 관리자 권한으로 cmd 창에서 Network Connections(ncpa.cpl)를 실행해도 막상 공유를 위한 메뉴는 관리자 비밀번호를 물어 본다. 그래서 다음과 같이 파워셸로 인터넷을 공유할 수 있었다.

# Register the HNetCfg library (once)
regsvr32 hnetcfg.dll

# Create a NetSharingManager object
$m = New-Object -ComObject HNetCfg.HNetShare

# List connections
$m.EnumEveryConnection |% { $m.NetConnectionProps.Invoke($_) }

# Find connection
$c = $m.EnumEveryConnection |? { $m.NetConnectionProps.Invoke($_).Name -eq "Ethernet" }

# Get sharing configuration
$config_main = $m.INetSharingConfigurationForINetConnection.Invoke($c)

# Find connection
$c = $m.EnumEveryConnection |? { $m.NetConnectionProps.Invoke($_).Name -eq "Ethernet 2" }

# Get sharing configuration
$config_pi = $m.INetSharingConfigurationForINetConnection.Invoke($c)

# Enable sharing (0 - public, 1 - private)
$config_main.EnableSharing(0)

# Enable sharing (0 - public, 1 - private)
$config_pi.EnableSharing(1)

7   Bonjour 서비스를 이용해서 파이에 접속하기

위와 같이 고정 IP 주소로 설정을 했으면 Bonjour 서비스를 사용할 필요가 없다. Bonjour 서비스는 동적으로 IP 주소를 호스트와 파이 모두에 할당하고 파이의 호스트명으로 접속할 수 있게 해 준다. 이를 위해서는 리눅스에는 avahi와 avahi-autoipd가 필요하고 윈도에는 Bonjour 서비스를 설치해야 한다. 윈도를 위한 Bonjour 설치 파일은 두 개가 있는데 Bonjour SDK for Windows를 설치하면 아무래도 군더더기가 적을 것 같다. 두 경우 모두 파이에는 avahi를 설치해야 된다.

get_picore_pkg를 이용해서 avahi 확장을 설치한다.

su - # 호스트의 root로 로그인한다.

mount /dev/mmcblk0p2 /mnt
cd /mnt/tce/optional

get_picore_pkg avahi

7.1   리눅스 호스트

파이에서 avahi 데몬을 실행할 스크립트를 작성한다. 아직 파이에 접속할 수 없으므로 호스트에서 작성한다.

mkdir /tmp/mydata
cd /tmp/mydata

tar xvfz /mnt/tce/mydata.tgz

chmod a-x home/tc/etc/rc.d/rc.usb0 # 고정 IP 주소 스크립트를 해제한다.

cat<<'EOT'> home/tc/etc/rc.d/rc.inet
#!/bin/sh
/usr/local/etc/init.d/dbus start
/usr/local/etc/init.d/avahi start
avahi-autoipd -D usb0
EOT
chmod a+x home/tc/etc/rc.d/rc.inet

chown -R 1001.50 home/tc/etc

tar cvfz /mnt/tce/mydata.tgz .

umount /mnt

cd /tmp
rm -rf mydata

SD 카드를 파이에 꽂고 호스트에 연결한다. 파이의 부팅이 끝나면 호스트에서 다음을 실행한다.

su -

# 파이의 부팅이 끝나면 Netchip Technology, Inc. Linux-USB Ethernet/RNDIS Gadget라는 USB 디바이스가 생성된다.
lsusb # 위의 디바이스가 보일 때까지 lsusb를 반복 실행한다.

# NetworkManager가 usb0의 연결을 끊어 버리는 것을 방지한다.
nmcli dev set usb0 managed no

/etc/rc.d/rc.avahidaemon start
avahi-autoipd -D usb0

# IP 포워딩을 활성화한다.
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

이제 ssh tc@box.local로 파이에 접속이 가능하다.

7.2   윈도 호스트

파이에서 avahi 데몬을 실행할 스크립트를 작성한다. 아직 파이에 접속할 수 없으므로 호스트에서 작성한다.

mkdir /tmp/mydata
cd /tmp/mydata

tar xvfz /mnt/tce/mydata.tgz

chmod a-x home/tc/etc/rc.d/rc.usb0 # 고정 IP 주소 스크립트를 해제한다.

cat<<'EOT'> home/tc/etc/rc.d/rc.inet
#!/bin/sh
/usr/local/etc/init.d/dbus start
/usr/local/etc/init.d/avahi start
avahi-autoipd -D usb0
udhcpc -iusb0&
EOT
chmod a+x home/tc/etc/rc.d/rc.inet

chown -R 1001.50 home/tc/etc

tar cvfz /mnt/tce/mydata.tgz .

umount /mnt

cd /tmp
rm -rf mydata

리눅스 호스트와 비교해서 마지막 DHCP 클라이언트를 실행하는 것이 다르다. 이는 파이와 호스트의 연결은 avahi-autoipd가 책임지지만 인터넷을 공유하는 설정을 해 버리면 호스트와 파이의 USB 인터페이스의 IP 주소가 Bonjour 서비스가 할당한 169.254.x.y에서 인터넷 공유 DHCP 서버의 새로운 IP 주소 192.168.137.z로 바뀌어 버린다. 그래서 이 주소를 받기 위해 파이측에서 DHCP 클라이언트가 필요하다. 리눅스의 경우에는 인터넷의 공유를 위해 따로 DHCP 서버나 클라이언트가 필요없다. 아직도 avahi가 파이에서 돌고 있으므로 여전히 ssh tc@box.local로 접속이 가능하다.

호스트에서 다음을 설정한다.

  • Control Panel ⇒
  • Network and Sharing Center ⇒
  • 주 네트워크의 Properties ⇒
  • Sharing ⇒
  • Allow other network users to connect through this computer’s Internet connection 활성화 ⇒
  • Home networking connection ⇒
  • USB 이더넷 네트워크 선택

8   관리자가 아닌 윈도 호스트에서의 문제

다 좋은데 인터넷을 공유하는 설정은 관리자만 켤 수 있다. 특정 프로그램을 돌릴 때 임시로 관리자 권한을 주는 기능이 있지만 Control Panel을 관리자 권한으로 돌릴 수는 없다. 그런데 레지스트리 에디터인 regedit는 관리자로 실행이 가능해 보인다. 그래서 레지스트리를 수정해서 인터넷을 공유하는 방법을 찾았다. 아직 해 보지는 않았다.

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Network Connections

  • NC_PersonalFirewallConfig (DWORD) = 1
  • NC_ShowSharedAccessUI (DWORD) = 1

여기 소개된 방법들도 시도해 보자.

참고문헌

이 칸을 비워 두세요.