AnonymousLANChat
LAN内のみで使える匿名性を高めたピュアP2Pのチャットソフトです.
同じPC教室にいる人同士で,同じオフィスにいる人同士で,学会で同じ発表を聞いている人同士で・・・匿名のチャットが出来たら便利だと思いませんか.匿名というと聞こえが悪いですが,講義・講演へのフィードバックなど有用な状況は色々と考えられます.
PC教室やオフィスでは室内のPCに規則的なプライベートIPアドレスが割り当てられています.また,学会・イベント会場に用意されているWIFIルーターに接続しているときは個人のプライベートIPアドレスはコロコロ変わります.そういった状況では(ルーターなどの設定に依りますが)UDPのブロードキャストを使ったノード検索が可能です.誰がチャットのネットワークに参加しているのか,LAN内のPCにブロードキャストするだけで調べられます.ピュア型P2Pを使い始めるときに必ず必要だった初期ノードの交換の手間を省略できる点がいいなと思って,このソフトを作成しました.
私は高校の卒業研究でマルチプラットフォーム対応のP2Pファイル共有ソフトの開発に関わっていましたが,Rubyではなくjavaで実装する事になってからは全てtondolが開発していました.私がjavaで実装したのは確かSwingのGUI部分くらいです(余談ですが「クリックしようとすると逃げるShareのようなSwingのダイアログ」なんかも作りました).AnonymousLANChatではそこでの経験が活きているものの,ソースコードなどは一切引用していません(後述の#ソースコードの概要のようにこれの機能自体はすごく単純です).
Contents |
特徴
- Windows/Max/Linux/Android 1.6以上 の4OSに対応
- 起動したら設定なしで即使い始められる
- LAN内だけで完結しているのでポート開放・初期ノード設定などの手間が必要ありません
- 発言に多段プロキシと同等の匿名性が保証される
- 通信内容は全てAESで暗号化
スクリーンショット
左から順にWindows7/Max OS X Lion/Ubuntu 11.04 Desktop/Nexus S(Android 2.3.4)/Xperia X10(Android 2.1-update1 で動作している様子.
ダウンロード
- Android向け https://market.android.com/details?id=com.usi3.anonymouslanchat
- PC向け up/AnonymousLANChat.jar
それぞれスクリーンショットに載っている環境で動作確認済みです
使い方
起動したら1行の方のテキストエリアに何か書きこんでSendボタンを押して下さい. 他に参加しているノードがいなかったら投稿が反映されません.
問題点
- 参加者が4人以下だと中継ノードがいないため匿名性が確保できない
- UDPのブロードキャストを監視し続ければチャットの参加者リストが作れる
オーバーレイの様子
非構造化オーバーレイで,メッセージは伝搬させて伝えます.一つのノードの同時接続数が多いとchurn耐性は強くなりますが,発言者の特定が簡単になってしまいます.そこで,最大接続数は4つまでにしました.端末同士のつながり方は次の画像の通りです(アルファベットはAから順に参加した順,矢印の元がconnectして先がaccept).
一気に4つ以上のノードが離脱しないと孤立ノードが生まれません.また,孤立した際には自動で繋ぎ直します.
ソースコードの概要
環境依存のGUI部分
AndroidのMainActivity.javaやSwingのMainFrame.javaからP2Pクラスのインスタンスとそのリスナーを通して
- Sendボタンが押されたらテキストボックスの内容をp2p.send
- P2PListenerのonStatusChangedにP2Pクラスの動向が流れてくるのでそれをログとしてGUIに流す
- 終了時はp2p.shutdown
などの処理をしています.
共通ライブラリ:P2P.java
public class P2P implements ConnectionListener { private UDPBroadcast broadcast; // ブロードキャストの送信と受信を担当 private P2PListener p2pListener; private Set<Connection> clients; // ノード間の接続の間には必ずConnectionクラス private Thread acceptThread; //他のノードからのconnectを待ってacceptしたりしなかったりするスレッド private ServerSocket serverSocket; // acceptThread用 private boolean destroyed; // // acceptThread用 private ScheduledExecutorService keepConnectedService; // 他のノードとの接続を保ち続けるための10sに1回色々する // P2Pクラスの動向は分かりやすく P2PListener を通して呼び出し元に伝える public P2P(final P2PListener listener) public boolean connect(String ip) public void send(String message) // 全ての clients にメッセージ送信 public void checkConnection() // clientsの接続確認 public void delete(String ip) // 接続が切れた接続を削除 public void shutdown() // ソフトの終了時に呼ぶ // ConnectionListener, clientsやbroadcastが受信した情報は全てここに集められる @Override public void onReceive(String message, String ip, int port) }
- Connection.java
Socketのラッパーのようなものです.
public class Connection { private Socket socket; private BufferedOutputStream out; private BufferedInputStream in; private P2PListener p2pListener; private ConnectionListener connectionListener; private Thread receiveThread; // 接続先からの返信を受け取るスレッド // acceptで得られるSocketのインスタンスを元にConnectionを作る public Connection(Socket socket, P2PListener p2pListener, ConnectionListener connectionListener) // ipとportを元にConnectionを作る public Connection(String ip, int port, P2PListener listener, ConnectionListener connectionListener) // リスナーを2つも渡していて気持ち悪いけどしょうがない・・・ public void start() // receiveThread開始 public boolean send(String message) // outにメッセージを書きこむ. public boolean isConnected() // 接続先と本当につながっているか? public String getIP() // socketから接続先のIPアドレスを取得して返す public void shutdown() // 終了時に呼ぶ }
- StringCrypt.java
シングルトンで,AESを使った暗号化と復号化を担当しています.ConnectionやUDPBroadcastの送受信部分では全てこのStringCryptをかまします.
public class StringCrypt { private static StringCrypt me; public StringCrypt() public static StringCrypt getInstance() public byte[] encrypt(String text) public String decrypt(byte[] encrypted, int size) }