P2Pにはあまり良いイメージを持っていないという人が多いかもしれません。しかしP2Pという技術に悪いことなんて何もなくて、一般的に利用されている技術です。今は違いますが、リリース直後のskypeでは利用者間でP2P通信を行っていました。
さて、今から15年くらい前、このP2P通信技術を使ってメッセージ交換を行うデータ分散型匿名掲示板システムの為のプロトコル(新月/shinGETsu)がネット上の有志で作られました。当時このプロトコル仕様を元にして、いくつかの実装が作られたようです。
一時期は盛り上がっていたようですが、現在はほとんど人がいません。おまけに現在も継続してメンテナンスされている実装は、python3で書かれている 朔(saku)だけなようです。ただ、接続ログを見ているとGo言語で書かれた合(gou)が動いているノードもいくつかあるようですが。
なぜ今sakuを運用するのか
以前動かしていた時はアクティブユーザが多く、掲示板にspamメッセージが大量に流れ込んだり、保存しているだけでも危険なファイルが流れてきたりと不穏な感じがしました。それが今ではユーザが減り当たり障りのないメッセージがたまに流れてくる程度で運用に気を気を使わなくて良くなりました。
常々pythonに慣れたいと思っている事もあって、適当なサイズのsakuはソースを読むのも勉強になるかなーとかとか。
朔(saku)をインストールして実行してみる
saku を動かすと決めたら、インストール前にいくつか決めなくてはならない事があります。
自分専用なのか、不特定多数に公開するのか
公開ゲートウェイノード(*1)のように不特定多数の人へ開放する事も、自分専用のノードとして運用する事も可能です。しかし、運用に慣れるまでは自分専用ノードとして運用するのが良いと思います。
(*1) 公開ゲートウェイノード情報は、https://shingetsu.info/ に載っています。
ノードの設置場所
saku をどこのサーバで動かすのか?という問題があります。自宅内に設置するのか、若しくは外部に設置するのか。それぞれで必要となる技術要件が異なってきます。慣れないうちは自宅の仮想環境などで何度か構築をしてみるのが良いと思います。
自宅に設置する
saku は(多分)起動時に直近の更新情報を取りに行くような動きをするので、24時間運用する必要はないかもしれません。しかし、この場合でも隣接ノードからの接続要求は受け入れる必要があります。
一般的な自宅のネットワーク環境は、境界にルータを設置しNAT等のアドレス変換をさせている事が多いと思います。なのでポートフォワーディングやIPフィルタリングを適切に設定する事が必要です。
外部に設置する
外部に遊んでいるサーバがあれば、そこに間借りするのも良いでしょう。稼働に必要なリソースが気になると思いますが、保持する掲示板のメッセージ量で変わってきます。保持するメッセージ数が少なければ、ほとんどリソースを使いません。
ぼくが動かしているノードでは保持している掲示板量がかなり少ないので、あまり参考にならないかもしれませんが、この位のリソース消費量です。
1 2 3 4 5 6 7 |
Status Linked Nodes 5 Known Nodes 13 BBSes 12 Articles 13826 Cache Size 32.3MB |
1 2 |
# du -hs /usr/local/saku-cache/ 115M /usr/local/saku-cache/ |
この状態でsaku が専有する物理メモリは30MBytes程度、ストレージ使用量は115Mバイトとわりとこじんまりとしています。ネットワーク転送量もテキストデータの転送が主体なので無視できるレベルです。
ところで外部サーバへsakuを設置する場合、自分が掲示板へアクセスするための手段を考えなくてはなりません。
公開ゲートウェイノードとして運用する場合でも管理者として接続する為には、接続元IPアドレスを設定ファイル内に記述しなくてはなりません(IPアドレスベースのACLになっている)
VPNを設置する等、いろいろな解決手段が考えられると思います。ぼくはお手軽に自宅の境界ルータと外部ノード間にGREトンネルを掘ってみました。
想定する環境
OS | Ubuntu 20.04 LTS |
saku 設置方法 | インストール型 |
自宅環境足回り | フレッツ光ネクスト PPPoE 接続 |
自宅環境N/W | 192.168.0.0/24 |
ノード側N/W | 172.16.1.0/24 |
関連ファイルツリー
Makefileに変更を加えなければ、saku は/usr/local/
以下にファイル一式がインストールされます。
近頃ではバージョンが上がる事はあまりないのですが、バージョンアップ時の作業を容易にする為にいくつか設置場所を変更しています。
/usr/local/saku-release-バージョン/
以下へ配置する- 設定ファイル、cacheディレクトリをsakuツリーの外側に作る
- symlinkを張り、バージョンアップ後も
/usr/local/saku
でアクセスできるようにしている
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/usr/local/ ├── etc │ └── saku ├── saku-cache ├── saku -> saku-release-4.9.1 └── saku-release-4.9.1 ├── bin ├── etc │ └── saku ├── share │ └── saku │ ├── file │ ├── template │ └── www └── var ├── log │ └── saku └── run └── saku |
インストール手順
windowsの事はよくわからないので、linux環境へのインストール方法になります。パッケージでは提供されていないので、ディストリビューションが異なっても基本的に同じ手順で設置できると思います。
pythonパッケージのインストール
1 2 3 4 |
$ sudo pip freeze | grep -E -i "jinja|markup" # jinja2,markupsafeが入っていなければ、パッケージをインストールする $ sudo apt install python3-jinja2 python3-markupsafe |
ソースファイルのダウンロード
1 2 |
$ git clone https://github.com/shingetsu/saku.git $ cd saku |
Makefileの変更
- インストールパスの変更
- 起動ファイルをinitからsystemdに変更
下記、パッチファイルをどこかに置いてからパッチを当てます。
1 |
$ patch -p1 < /somewhere/patch_file |
以下パッチファイルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
diff --git a/tool/git2ver.sh b/tool/git2ver.sh index 8c5e656..0d372a6 100755 --- a/tool/git2ver.sh +++ b/tool/git2ver.sh @@ -1,5 +1,13 @@ #!/bin/sh # git log format to version string # +if [ "$1" = "git-long" ];then + echo "$(git describe --tags)-$(date +%Y%m%d)" +elif [ "$1" = "git-short" ]; then + echo "$(git log --abbrev-commit -1 --oneline|cut -c 1-7)"-$(date +%Y%m%d) +elif [ "$1" = "version" ];then + echo "$(git describe --abbrev=0)" +else git log -n 1 --pretty=format:"%ai" | env TZ=UTC xargs -0 date +'%Y%m%d-%H%M' --date +fi diff --git a/Makefile b/Makefile index b61d69f..e5a152c 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,10 @@ # Copyright (C) 2005-2014 shinGETsu Project. # -PREFIX = /usr/local PACKAGE_DIR = .. PACKAGE = saku-$(shell cat file/version.txt) +RELEASE = saku-$(shell ./tool/git2ver.sh version) +PREFIX = /usr/local/$(RELEASE) .PHONY: all install exe version check clean distclean package @@ -14,10 +15,16 @@ all: install: python3 setup.py install --prefix=$(PREFIX) + -mv -f /etc/init.d/saku /etc/init.d/.saku + cp -f saku.service /etc/systemd/system/ + systemctl daemon-reload version: ./tool/git2ver.sh > file/version.txt +git-version: + ./tool/git2ver.sh git-short > file/version.txt + check: sh tests/runtests.sh @@ -26,6 +33,7 @@ clean: rm -f www/__merged.css www/__merged.js rm -Rf build dist root rm -Rf cache log run + rm -f file/version.txt find . -name "*.py[co]" \! -path ".git/*" -print0 | xargs -0 -r rm -f -find . -type d -name "__pycache__" -print0 | xargs -0 -r rmdir diff --git a/saku.service b/saku.service new file mode 100644 index 0000000..96ca7f3 --- /dev/null +++ b/saku.service @@ -0,0 +1,14 @@ +[Unit] +Description=Saku - a clone of P2P anonymous BBS ShiGETsu +After=network.target + +[Service] +Type=simple +Environment=PYTHONPATH=/usr/local/saku/lib/python3.7/site-packages +ExecStart=/usr/local/saku/bin/saku +ExecStop=/bin/kill -TERM $MAINPID +PIDFile=/usr/local/saku/var/run/saku/pid.txt +Restart=on-failure + +[Install] +WantedBy=multi-user.target |
saku をインストール
インストールしてから、symlinkを張り、cacheディレクトリ作成、設定ファイルの設置を行います。
1 2 3 4 5 6 7 |
$ sudo make install $ sudo mkdir -p /usr/local/etc/saku/ $ sudo ln -s /usr/local/saku-release-4.9.1 /usr/local/saku $ sudo cp -pi doc/sample.ini /usr/local/etc/saku/saku.ini $ sudo mkdir -p /usr/local/saku-cache $ sudo vi /usr/local/etc/saku/saku.ini |
バージョンアップがあった場合は、同様にインストールをしてから symlink を張り替えればキャッシュと設定ファイルを再利用できます。
設定ファイルを設置
起動前に/usr/local/etc/saku/saku.ini
を設定します。これを忘れてsaku を起動してしまうと、想定していないところにディレクトリが掘られたりファイルが配置されたりと混乱の元になります。
pathセクションは間違えやすいので、よく確認すること。重要なのはprefix
,cache_dir
です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[Path] prefix: /usr/local/saku var: %(prefix)s/var sysconfig: %(prefix)s/etc docroot: %(prefix)s/share/saku/www file_dir: %(prefix)s/share/saku/file template_dir: %(prefix)s/share/saku/template log_dir: %(var)s/log/saku run_dir: %(var)s/run/saku cache_dir: /usr/local/saku-cache spam_list: %(sysconfig)s/saku/spam.txt initnode_list: %(sysconfig)s/saku/initnode.txt node_allow: %(sysconfig)s/saku/node_allow.txt node_deny: %(sysconfig)s/saku/node_deny.txt apache_docroot: %(var)s/www/shingetsu archive_dir: %(var)s/www/archive |
Gatewayセクションは、IPアドレスベースのACL設定を書いていきます。
うちの環境は、家庭内NWが192.168.0.0/24
なので以下のようになります。公開ゲートウェイノードにするのならば、visitorの項目を
visitor: .
と記述します。
1 2 3 4 5 6 7 8 9 |
# The IP address of administrator. admin: ^(127|192.168.) # The IP address of users who can get cache from network. (regular expression) friend: ^(127|192.168.) # The IP address of users who can use gateway. (regular expression) #visitor: . visitor: ^(127|192.168.) |
その他、掲示板の保存期間等の項目は好みでどうぞ。
saku の起動
ノードが再起動した時でも自動的にプロセスを起動するように enable
指定しておきます。
1 2 3 4 5 |
# 自動起動設定 $ sudo systemctl enable saku # プロセス起動 $ sudo systemctl start saku |
ログは/usr/local/saku/var/log/saku/%Y-%m-%d
に出力されます。しばらく待っていると他ノード間でpingを送ったりjoinしている様子が見えると思います。
自宅内NWからsaku へ接続
さて、外部サーバ上で無事にsaku プロセスを起動できたと思います。しかし、IPアドレスベースのACLがかかっているのでhttp//IPアドレス:8000/
にアクセスしても、掲示板を読むことができません。
そこで、自宅の境界ルータ – 外部サーバ間にGREトンネルを張り、掲示板を読めるように設定していきます。
ネットワーク | MTU | |
自宅境界ルータ | 192.168.0.0/24 | 1454 |
外部サーバ | 172.16.1.0/24 | 1500 |
自宅境界ルータ
自宅の足回りはフレッツ光ネクストを使い、PPPoEで接続しています(MTU: 1454)
1 2 3 4 5 6 7 8 9 10 11 |
# GREトンネルを設置 $ sudo ip tunnel add vps0 mode gre remote 外部サーバのIPアドレス local 自宅のIPアドレス ttl 64 # フレッツ光ネクストのMTU(1454) - GREヘッダ(24) = 1430 $ sudo ip link set mtu 1430 dev vps0 # link up sudo ip link set up dev vps0 # 外部サーバの内側NWへのルーティングを vps0 へ向ける sudo ip route add 172.16.1.0/24 dev vps0 |
外部サーバ
外部サーバはethernet(MTU:1500)で接続されていますが、対向のMTUと合わせて MTUを1430に設定します。
1 2 3 4 5 6 7 8 9 10 11 12 |
# loopbackインターフェイスにsecondary ip addr.を付与 $ sudo ip addr add 172.16.1.1/24 dev lo # 自宅との間にGREトンネルを設置 $ sudo ip tunnel add home0 mode gre remote 自宅のIPアドレス local 外部サーバのIPアドレス ttl 64 # 自宅回線のMTUに揃える $ sudo ip link set mtu 1430 dev home0 $ sudo ip link set up dev home0 # 自宅への戻りルートを設定 $ sudo ip route add 192.168.0.0/24 dev home0 |
疎通の確認
互いにpingを打って確認していきます。
自宅 → 外部サーバ
複数のIPアドレスを持っているノードの場合は、pingを打つときにsrc addr.を指定すべきです。意図しないsrc addr.で送信すると戻り経路が無くてdefault routeへ送られた結果、疎通に失敗と誤解される事が割とよくあります。
1 2 3 4 5 6 7 8 9 10 11 |
$ ping -c 5 172.16.1.1 -I 192.168.0.1 PING 172.16.1.1 (172.16.1.1) from 192.168.0.1 : 56(84) bytes of data. 64 bytes from 172.16.1.1: icmp_seq=1 ttl=64 time=9.08 ms 64 bytes from 172.16.1.1: icmp_seq=2 ttl=64 time=5.09 ms 64 bytes from 172.16.1.1: icmp_seq=3 ttl=64 time=5.09 ms 64 bytes from 172.16.1.1: icmp_seq=4 ttl=64 time=5.24 ms 64 bytes from 172.16.1.1: icmp_seq=5 ttl=64 time=5.35 ms --- 172.16.1.1 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 8ms rtt min/avg/max/mdev = 5.091/5.971/9.083/1.560 ms |
外部サーバ → 自宅
戻りも問題ない事が確認できました。
1 2 3 4 5 6 7 8 9 10 11 |
$ ping -c 5 192.168.0.1 -I 172.16.1.1 PING 192.168.0.1 (192.168.0.1) 送信元 172.16.1.1 : 56(84) バイトのデータ 64 バイト応答 送信元 192.168.0.1: icmp_seq=1 ttl=64 時間=5.19ミリ秒 64 バイト応答 送信元 192.168.0.1: icmp_seq=2 ttl=64 時間=4.95ミリ秒 64 バイト応答 送信元 192.168.0.1: icmp_seq=3 ttl=64 時間=5.03ミリ秒 64 バイト応答 送信元 192.168.0.1: icmp_seq=4 ttl=64 時間=5.02ミリ秒 64 バイト応答 送信元 192.168.0.1: icmp_seq=5 ttl=64 時間=4.91ミリ秒 --- 192.168.0.1 ping 統計 --- 送信パケット数 5, 受信パケット数 5, パケット損失 0%, 時間 4005ミリ秒 rtt 最小/平均/最大/mdev = 4.908/5.018/5.186/0.095ミリ秒 |
もしも通らないときは、tcpdumpを使いパケットを確認してみましょう。
1 |
$ sudo tcpdump -i any -n proto gre |
掲示板へアクセス
自宅PCからブラウザでアクセスしてみます。IPアドレスは、外部サーバの内側のIPアドレスです。 http://172.16.1.1:8000/
技術的課題
外部サーバ上で無事にsakuを動かすところまで成功しましたが、いくつかの技術的な課題が残っています。
- 自宅のIPアドレスが変更された時、GREトンネルを自動で張り直すようにしたい
- 外部サーバが再起動された時、GREトンネルを自動で張るようにしたい
- 外部からのリクエストをsakuが直接受けるのではなくnginx等でreverse proxyしたい
- 古いsaku で実装されていた、過去の掲示板データを自動収集する仕組みを組み込みたい
- etc…
分散掲示板システムなので、いつでもプロセスを落として実験できるのも気が楽で良いところです 🙂