もぐてっく

人は1つ歳をとるたび、1ビットづつ大きくなれると信じてた。

IPアドレス固定なしで家庭内サーバをインターネットに公開できるデーモンを作ったよ

何これ

自宅サーバを公開したい!
→ルータのポートマッピングを設定しないといけない!
→サーバのIPアドレスを固定しないといけない!
→IPアドレスの管理めんどい!DHCPのまま公開したい!

と言う、おおよそサーバ管理者に向かないものぐさ思考をUPnPを使って解決することにしました。

UPnPとは、ネットワーク内でのサービス提供者の発見、サービス内容の公開、リモートプロシージャコールを行う仕組みです。10年以上前からあるふっるい技術ですね。

当時はWebサービスマッシュアップ技術の本命だったのですが、結局、サービス探索なんてあんま使わないじゃん。RPCはシンプルなRESTでいいじゃん。となって流行る前に忘れられた感があります。

そんなわけで、UPnPを使ってて広く実用化されているのはルータのポート開放とDLNA位と言うのが現状です。

UPnPでのポート開放は通常はメッセンジャーなどのアプリケーションが自分用のポートを開けるために使用しますが、今回、これを使って任意のポートを制御するデーモンを作ってみました。

こだわったところ

mDNSとの親和性

mDNS(avahi、bonjour)を使えば、ローカルなDNSサーバがなくとも「ホスト名.local」と言う名前で端末にアクセスできるようになります。これを使えばDHCPでころころIPアドレスが変わる端末にも、ホスト名でアクセスできるということです。素晴らしい。

今回作ったデーモンはこの素晴らしいmDNSとの連携を意識した設計になっています。

デーモンは定期的にホスト名を正引きして、IPアドレスが変わっていた場合はルータにポートマッピングの再登録を行います。
この動きにより、ポート転送先サーバとして「ホスト名.local」を指定していれば、たとえサーバのリブートでDHCPから払い出されるIPアドレスが変わったとしても、ポート転送を追従させることができます。

これによって当初の「DHCP環境でもサーバ公開したい!」が達成できるというわけです。

集中管理にも分散管理にも使えます

このデーモンはデーモンが動作しているサーバへのポート転送の他に、別のサーバへのポート転送も設定することができます。

なので、管理サーバ立ててネットワーク内のすべてサーバのポートマッピングを集中管理することもできますし、それぞれのサーバでデーモンを動かして各サーバに自分が使うポートの管理を任せることもできます。

ダウンロード

github.com

インストール

Ruby開発キットをインストールする

apt-get install ruby ruby-dev build-essential

mupnp gemをインストールする

gem install mupnp

設定ファイルを編集して/etc/にコピーする

cp -p pnp_portmapd.conf.sample /etc/pnp_portmapd.conf

デーモンを起動する。

./pnp_portmapd

設定ファイル

YAML記法になってます。
JSONと違ってコメントが書き放題なのが良いですね。

# 設定
Settings:
  # ポートマッピング更新周期(秒)
  Period: 5

# ポートマッピング定義
PortMapping:
  # 転送先ホスト名
  akari.local:
   - ExtPort: 82   # 外部ポート
     IntPort: 81   # 転送先ポート
     Protocol: TCP # プロトコル(TCP/UDP)
   - ExtPort: 100
     IntPort: 101
     Protocol: UDP

  alicia.local:
   - ExtPort: 101
     IntPort: 102
     Protocol: UDP

この設定を適用すると、うちのルータではこんな感じになります。
akari.localが192.168.11.17、alicia.localが192.168.11.11です。
両者ともIPアドレスDHCPから払い出されたものであり、IPアドレス固定なしでサーバが公開できています。

f:id:moguno:20151126120957p:plain

ログファイル

/var/log/pnp_portmapd.logです。
ルータに設定を行うたびにINFOメッセージを出しているので、眺めてると楽しいです。

ライセンス

License: 3 clauses BSDとやらにします。