anyPi(ラズパイ+3GPi)で固定IPアドレスSIMイプシムを使う

ラズベリーパイ用3G通信モジュール「[3GPi](https://mechatrax.com/products/3gpi/)」・ラズパイ本体・コンソールI/Fモジュールなどがセットになった、[メカトラックス様](https://mechatrax.com/)の「[anyPi](https://mechatrax.com/products/anypi/)」で、グローバルIPアドレス固定割当の格安SIM[イプシム](https://ipsim.net/)を使ってみます。
![anyPi.jpg](https://qiita-image-store.s3.amazonaws.com/0/211762/9547d183-1172-2ca8-1448-9c0e2918805e.jpeg)

#何ができるの？
有線LAN・無線LANが無い環境でも、外部からラズパイを制御できます。

##ポイント

- ラズパイに直接グローバルIPアドレスが割り当てられます → APNを設定するだけ！
- Internet側からラズパイに接続可能です → ufwで必要な通信のみ許可します

※デフォルトの状態で使うと危険です。必ずufwやiptablesの設定を行いましょう。

##準備するもの
![ipsim.jpg](https://qiita-image-store.s3.amazonaws.com/0/211762/4af8b5df-1f10-8140-90e7-4e0576b2f48b.jpeg)

- ラズパイIoTスタータキット「[anyPi](https://mechatrax.com/products/anypi/)」 ※ラズパイ＋3GPiだけでも大丈夫です
    - Raspberry Pi 3 Model B
    - ラズベリーパイ用3G通信モジュール「[3GPi](https://mechatrax.com/products/3gpi/)(Ver.2)」
    - コンソールI/Fモジュール「PiConcole I/F」
    - Raspbian構築済microSDカード([3gpi2-jessie-20170904](https://github.com/mechatrax/3gpi/tree/master/release))、ACアダプタ、ケーブルなど
- 固定IPアドレスMVNO「[イプシム](https://ipsim.net/)」標準SIM
- 設定用PC（またはモニタ・キーボード）
- DHCPが有効な有線LAN

#開封から接続まで
##セットアップ（約3分）
![3GPi.jpg](https://qiita-image-store.s3.amazonaws.com/0/211762/327c1378-6fa3-53e9-0150-ef07fb05aa69.jpeg)

1. anyPiを組み立て、3GPiにイプシムのSIMカードを取り付け[^1]ます。
2. PiConsole I/FのUSBシリアルをPCに接続[^2]（またはラズパイにモニタ・キーボードを接続）します。
3. 初期設定のため有線LANに接続し、起動します。

[^1]: nano SIM＋変換アダプタを使いましたが、標準SIMの利用が無難です。
[^2]: [Raspberry Pi で syslog に rsyslogd-2007: action 'action 17' suspended が出た時の対策](https://qiita.com/sakasa/items/47f58da8eda7d792ab10)を行いました。

##初期設定（約10分）

1. なにはともあれ、まずはufwのインストール、設定を行います。
    インストール

    ```
sudo apt-get install ufw
```

    IPv6無効

    ```
sudo vi /etc/default/ufw
```

    ```text:/etc/default/ufw
#IPV6=yes
IPV6=no
```

    全てを拒否し、ローカル(192.168.0.0/24)からのssh接続のみ許可

    ```
sudo ufw default deny
sudo ufw allow from 192.168.0.0/24 to any port 22 proto tcp
```

    default denyでもpingには応答してしまうので、ppp0（SIM側）のみ拒否

    ```
sudo vi /etc/ufw/before.rules
```

    ```text:/etc/ufw/before.rules
#「# ok icmp codes」の直前
# ppp0
-A ufw-before-input -p icmp -i ppp0 --icmp-type echo-request -j DROP
```

    ufw有効化、状態確認

    ```
sudo ufw enable
sudo ufw status
```

    

1. イプシムのAPNを設定します。
    イプシムはanyPi/3GPi付属のmicroSDにはプリセットされていないので、手動で[APN情報](https://ipsim.net/support.html)を設定

    ```
sudo nmcli con add type gsm ifname "*" con-name ipsim.net apn 4gn.jp user sim@with password sim
```

1. いったん電源をOFF、有線LANを取り外します。

    ```
sudo shutdown -h now
```

##接続確認（約3分）
![3GPi_LED.JPG](https://qiita-image-store.s3.amazonaws.com/0/211762/dbe9ad5d-554f-b17c-a8cd-4eacbe76c118.jpeg)

1. 電源をON、3GPiの青色LEDが
    `《点灯》→《ゆっくり点滅》→《はやい点滅》`
    と変化することを確認します。

1. nmcliコマンド

    ```text:nmcli(1)
$ nmcli con
NAME              UUID                                  TYPE     DEVICE
gsm-3gpi-iij      02cd067e-10d5-40a6-8aaf-************  gsm      --
ipsim.net         136604d4-df06-4f5b-91f8-************  gsm      ttyUSB3
gsm-3gpi-soracom  f297495c-9991-4b21-a811-************  gsm      --
ppp0              fb02a76b-4e2e-478e-bafd-************  generic  ppp0
```

    ```text:nmcli(2)
$ nmcli dev status
DEVICE   TYPE      STATE      CONNECTION
ttyUSB3  gsm       connected  ipsim.net
ppp0     ppp       connected  ppp0
eth0     ethernet  unmanaged  --
lo       loopback  unmanaged  --
wlan0    wifi      unmanaged  --
```

    → ~~iijさんやsoracomさんが見えますが気にせずに~~ DEVICEにttyUSB3とppp0が表示されること、STATEがconnectedになっていることを確認します。

1. ifconfigコマンド

	```text:ifconfig
	$ ifconfig -a
	eth0      Link encap:Ethernet  HWaddr b8:27:eb:xx:xx:xx
	          UP BROADCAST MULTICAST  MTU:1500  Metric:1
	          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
	          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
	          collisions:0 txqueuelen:1000
	          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

	lo        Link encap:Local Loopback
	          inet addr:127.0.0.1  Mask:255.0.0.0
	          UP LOOPBACK RUNNING  MTU:65536  Metric:1
	          RX packets:128 errors:0 dropped:0 overruns:0 frame:0
	          TX packets:128 errors:0 dropped:0 overruns:0 carrier:0
	          collisions:0 txqueuelen:1
	          RX bytes:10368 (10.1 KiB)  TX bytes:10368 (10.1 KiB)

	ppp0      Link encap:Point-to-Point Protocol
	          inet addr:XXX.XXX.XXX.XXX  P-t-P:10.64.64.64  Mask:255.255.255.255
	          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
	          RX packets:409 errors:0 dropped:0 overruns:0 frame:0
	          TX packets:446 errors:0 dropped:0 overruns:0 carrier:0
	          collisions:0 txqueuelen:3
	          RX bytes:36906 (36.0 KiB)  TX bytes:51480 (50.2 KiB)

	wlan0     Link encap:Ethernet  HWaddr b8:27:eb:xx:xx:xx
	          UP BROADCAST MULTICAST  MTU:1500  Metric:1
	          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
	          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
	          collisions:0 txqueuelen:1000
	          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

	wwan0     Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
	          BROADCAST MULTICAST  MTU:1500  Metric:1
	          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
	          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
	          collisions:0 txqueuelen:1000
	          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
	```

    →ppp0にグローバルIPアドレス(XXX.XXX.XXX.XXX)が割り当てられていることを確認します。

1. netstatコマンド

    ```text:netstat
$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.64.64.64     0.0.0.0         UG        0 0          0 ppp0
10.64.64.64     0.0.0.0         255.255.255.255 UH        0 0          0 ppp0
```

    →まぁ、PPPですからね。

#実際に接続してみる

##ラズパイからInternetに接続

- pingなどで実際の接続や名前解決を確認します。

##Internet側からラズパイに接続

1. 接続元のグローバルIPアドレス(YYY.YYY.YYY.YYY)を確認し、ufwに許可設定を追加します。

    ```
sudo ufw allow from YYY.YYY.YYY.YYY to XXX.XXX.XXX.XXX port 22 proto tcp
```

1. ufwのstatusを確認します。

	```text:ufw
	$ sudo ufw status verbose
	Status: active
	Logging: on (low)
	Default: deny (incoming), allow (outgoing)
	New profiles: skip

	To                         Action      From
	--                         ------      ----
	22/tcp                     ALLOW IN    192.168.0.0/24
	XXX.XXX.XXX.XXX 22/tcp     ALLOW IN    YYY.YYY.YYY.YYY
	```

1. 実際に手元のPCからInternet経由でラズパイに接続してみます。
    3G通信のため若干のタイムラグはありますが、sshは問題なく使えました。

1. 後は、ufwに必要な許可設定を追加します。

##ラズパイからラズパイに接続

- 同一構成を2つ以上用意すると、ラズパイ⇔ラズパイ間の接続も可能です。

#最後に
anyPi/3GPi付属microSDのRaspbianを使うと、後はufwのインストール＆設定とAPN設定だけで、Internet側からラズパイを制御可能な環境が出来上がります。まさにIoTスタータキット、とても簡単ですね。

###補足：PiConsole I/Fについて
単品販売は無くanyPi同梱のみのようですが、PCのUSBポートに接続するだけでラズパイにシリアル接続ができて便利です。その他にも、16文字x2行のテキスト表示ディスプレイ、LED、タクトスイッチ、電子ブザー等が搭載されています。[メカトラックスのラズパイIoTスタータキット「anyPi（エニーパイ）」のPiConsole I/Fを使ってみた](https://qiita.com/syasuda/items/5e1da8f3315e3031684a)に詳しくまとめられており、とても参考になります。ほとんど同記事からの抜粋になりますが、

>スイッチを押す → イプシムの固定IPアドレスや3G回線の接続状況をディスプレイに表示する

といったことも簡単に実現できましたので、手順をまとめておきます。

- I2Cの有効化

    ```
sudo raspi-config
```
起動後「5 Interfacing Options」→「P5 I2C」をenabledに変更

- i2c-toolsはインストール済みだったたため、wiringpiのみ追加インストール

    ```
sudo pip3 install wiringpi
```

- [WiringPi-Pythonを使ってAQM0802A / ST7032i LCD表示](https://qiita.com/f_nishio/items/b1b99b4763993a9239c6)のst7032i.pyを修正

    ```
vi st7032i.py
```

    ```python:st7032i.py
#import wiringpi2 as wp
import wiringpi as wp
````

- python3-dbusとpython-networkmanagerをインストール

    ```
sudo apt-get install python3-dbus
sudo pip3 install python-networkmanager
```

- サンプル3と6を合わせたスクリプトを作成

	```python:b36.py
	#!/usr/bin/env python3
	# -*- coding:utf-8 -*-

	import wiringpi as wp
	PIN_SW1_WHITE = 19
	PIN_SW2_BLACK = 16
	PIN_LED1_RED = 20
	PIN_LED2_YELLOW = 21
	PIN_BUZZER = 25

	import sys, socket, struct
	from fcntl import ioctl
	SIOCGIFADDR = 0x8915

	from st7032i import St7032iLCD as LCD
	I2C_ADDR_LCD = 0x3e

	import NetworkManager
	c = NetworkManager.const

	def get_ip(interface):
	    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	    try:
	        ifreq  = struct.pack(b'16s16x', interface)
	        ifaddr = ioctl(s.fileno(), SIOCGIFADDR, ifreq)
	    finally:
	        s.close()
	    _, sa_family, port, in_addr = struct.unpack(b'16sHH4s8x', ifaddr)
	    return (socket.inet_ntoa(in_addr))

	if __name__ == '__main__':
	    wp.wiringPiSetupGpio()
	    wp.pinMode(20,1)
	    wp.pinMode(21,1)
	    wp.pinMode(25,1)
	    lcd = LCD(I2C_ADDR_LCD)
	    while True:
	        sw1 = wp.digitalRead(PIN_SW1_WHITE)
	        sw2 = wp.digitalRead(PIN_SW2_BLACK)
	        if sw1 == 0:
	            lcd.clear()
	            wp.delay(250)
	            lcd.set_cursor(0, 0)
	            lcd.print("ppp0:")
	            ip_addr_ppp0 = get_ip(b'ppp0')
	            lcd.set_cursor(0, 1)
	            lcd.print(ip_addr_ppp0)
	        wp.delay(250)
	        if sw2 == 0:
	            lcd.clear()
	            wp.delay(250)
	            lcd.set_cursor(0, 0)
	            lcd.print("state:")
	            state = "{0}".format(c('state', NetworkManager.NetworkManager.State))
	            lcd.set_cursor(0, 1)
	            lcd.print(state)
	        wp.delay(250)
	```

- 実行

    ```
sudo python3 b36.py &
```

- スイッチ操作
    白SW1を押すとイプシムの固定IPアドレスが、黒SW2を押すと3G回線の接続状況がそれぞれ表示されます。
    白SW1で固定IPアドレスが表示されない場合は、黒SW2で3G回線の接続状況を確認する、といった使い方が考えられますね。