LAN内にあるデバイスがLAN内のポート80にのみアクセスができるようなものが存在します。そのポート自体の変更はできないので、アクセスされる側での対応を求められます。ただ、80番ポートはHTTPで使用されることも多いので、できれば開けておくことができれば後々便利かもしれません。そこでいろいろ調べてみたのですが、Linuxなどではネットワークインターフェース(以降NIC)に複数のIPアドレスを設定する(セカンダリIP)ことができるようです。
今回はRaspberryPiの無線LANのNIC(WLAN0)へセカンダリIPを設定し、ポートフォワードを行ってプライマリIP側の別のポートで受信待ちをしているプロセスに処理をさせようと思います。
今回の設定を図に表すと以下のようになります。
セカンダリIPを設定する
IPの設定を行う場合にはifconfigコマンド
とipコマンド
の2つの方法が考えられます。現在はipコマンドの方が推奨されているのでそちらを使用してみます。
今回はwlan0にセカンダリIP(192.168.0.100
)を設定します。
追加する場合
$ sudo ip addr add 192.168.0.100/24 dev wlan0
コマンドを実行すると、この様に追加されます。※今回はプライマリIPは192.168.0.7
となっています。
設定前
設定後
実際にpingでアクセスを確認してみます。
ちなみにこの設定を削除する場合には以下の様に行います。
削除する場合
$ sudo ip addr del 192.168.0.100/24 dev wlan0
注意点ですが
- ipコマンドで追加の作業をしてもセカンダリのIPは保存されません。再起動すると初期化されてしまいます。
rc.local
などのファイルでコマンドの実行を行うことも考えられますが、DHCPでのIP取得より先にこのコマンド処理が行われるので、プライマリとセカンダリの対応は逆転します。後述のポートフォワードの処理もうまく行かないようです。
ipコマンドのサブコマンドにはip addr save
をつかうことでセーブはできるようなのですが、データの保存だけで永続的にしようできるようにはなっていないのでした。多分servicectrl
などを使用して、細かい設定を行えばできるかもしれません。情報が少なかったので調べられなかったのが残念です。(ちなみに保存した設定の復元はip addr restore
を使います)
ポートフォワードを使用してセカンダリIPの80番ポートを8000番ポートに転送する
iptablesコマンド
を使用することで設定を行うことができます。
セカンダリIPのポート80からプライマリIPのポート8000へリダイレクトを行う設定
$ sudo iptables -A PREROUTING -t nat -p tcp -m tcp -d 192.168.0.100 --dport 80 -j REDIRECT --to-port 8000
このコマンドを実行することで192.168.0.100
の80番ポートへのアクセスをプライマリIPの8000番ポートへ転送を行っています。
こちらの設定も再起動などを行うと消えてしまいます。その場合は以下の手順を行うことで設定を永続的にさせることができます。
iptablesコマンド
の設定を永続化させる
iptablesコマンド
の設定を永続化させるにはiptables-persistent
というパッケージが必要です。以下を実行してインストールを行います。
$ sudo apt update $ sudo apt install iptables-persistent
インストール中に、「現在のIpv4ルールを保存しますか?」と表示されたら【はい】を選択します。
続けて「現在のIpv6ルールを保存しますか?」と表示されたら、【はい】を選択します。
インストール前に既に設定が終わっていたら、これで設定は永続化の設定は完了しています。 もし、設定がされていないようであれば以下のコマンドで設定を保存します。
$ sudo /sbin/iptables-save > /etc/iptables/rules.v4
永続化が行われていれば、Raspberry Piを再起動しても設定はそのまま保存されています。
ちなみに保存された設定は以下のようになっていました。
~$ cat /etc/iptables/rules.v4 # Generated by xtables-save v1.8.2 on Mon Aug 17 00:52:57 2020 *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A PREROUTING -d 192.168.0.100/32 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8000 COMMIT # Completed on Mon Aug 17 00:52:57 2020 # Generated by xtables-save v1.8.2 on Mon Aug 17 00:52:57 2020 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT # Completed on Mon Aug 17 00:52:57 2020
これでポートフォワードの設定は完了しました。
念の為今回の設定をシェルスクリプトにしたものが以下になります。 IPアドレスが設定されているかは確認して、設定済みであればなにもしないようにしています。
設定スクリプト
#!/bin/bash ## IPが含まれるかどうか調べる if [ "`hostname -I | grep '192.168.0.100'`" ]; then echo "設定済のため処理終了" else echo "未設定のため設定実行" sudo /sbin/ip addr add 192.168.0.100/24 dev wlan0 sudo /usr/sbin/iptables -A PREROUTING -t nat -p tcp -m tcp -d 192.168.0.100 --dport 80 -j REDIRECT --to-port 8000 fi
動作をテストしてみる
あとは動作のテストを行ってみます。ポート番号を指定する簡単なHTTPサーバはワンライナーでpython3 -m http.server 8000
こんな風に
書くことができますが、今回はIPとポート番号を指定する必要があるので、pythonでのコードを書く必要があります。(多分)
server.py
import http.server import socketserver IP = '192.168.0.7' # RaspberryPiのプライマリIPアドレス PORT = 8000 # ポートフォワード先 Handler = http.server.SimpleHTTPRequestHandler httpd = socketserver.TCPServer((IP, PORT), Handler) print('serving at IP', IP) print('serving at port', PORT) httpd.serve_forever()
こちらのコードを以下のように実行して
$ python3 server.py
WebブラウザからセカンダリIPへHTTPのアクセスを行うと以下のような画面になります。
コンソール画面
ブラウザ画面
これで無事にセカンダリIPに対してHTTPの処理をポートフォワードすることができました。
おわりに
これで、1つのNICに複数のIPアドレスを割り当てて、更にポートフォワードで処理を行うことができました。
LAN内のポート80にのみアクセスできるデバイスに関してもこれでなんとか対応できそうです。
今回のポートフォワードを行ってしまえばsudo権限
でないと扱うことができなかったwell-known port
へのアクセス対応も容易に可能です。
これまで、1つのネットワークインターフェースに複数のIPを振ることができるとは全く思っていませんでした。 ネットを検索しているとWindowsなどでもできるというような記述もありましたのでいつか試してみようかな。
ちなみに、今回問題考えていたLAN内のポート80にのみアクセスできるデバイスとは、Amazon Echoとなります。 次回以降でAmazon Echoを使った音声認識を行っていこうと思います。