rutrackerのクライアント例を使用して、Androidアプリケーションへの簡単なtor統合

私は、Androidアプリケーションでトーラスを介したプロキシを簡単に追加できるかどうか長い間疑問に思っていました。 それはかなり明白なタスクのように思えますが、トレントブラウザはすでにこのプラットフォームで長い間使用されています...しかし、見た目よりも複雑なタスクがたくさんあります。 せっかちな人のために、私はすぐに言います-はい、できます。 特に、最初から掘るのではなく、私のベストプラクティスを使用する場合。



たとえば、rutrackerで作業するためにアプリケーションを使用します。真空中の球形の馬で機能するコードが好きな人はいません。 以前は、このアプリケーションはGoogle Compression Proxyの助けを借りてブロック回避していましたが、残念ながら、ルートトラッカーまたはGoogleのいずれかがこのプロキシでの許可の可能性を排除していました。 もちろん、ロックをバイパスしてテレビ番組を簡単に視聴するために使用するvpnやその他のあらゆる種類のものがあることは言うまでもありません。 しかし、これはそれについてではありません。 ご存じのとおり、torはモバイルアプリケーションで非常に多くの用途に使用できます。たとえば、.onionでWebサイトにアクセスしたり、特に安全なメッセンジャーを実装したりできます。



Thorで動作するようにライブラリを接続する方法



ゼロから組み立てる方法



最初から組み立てる必要がない場合は、次のヘッダーに直接進んでください。



それで、完成したツールキットからこのトピックについて私たちが持っているもの。 Microsoftが率いる一部の人からの特別なリポジトリがあります(地下室のリンク)。 すべてが彼らのために働いたように思えます-しかし、品質と組み立てのメカニズムは単に恐ろしいです。 そして、リポジトリは2年間古くなっています。 そして、ライブラリのコンパイルされたバージョンはそこにありません。自分でそれを組み立てる方法についてはかなり馬鹿げた指示しかありません(「私はそれをやったのですが、理由はわかりませんが、それなしでは機能しません」というスタイルで)。 ただし、利用可能な指示は、コードを現在の状態に更新し、すべての奇妙な妨害を修正するのに十分です。



  1. このリポジトリのクローンを作成しています。



  2. そこでトーラス管理を担当するコンポーネントjtorctlを更新します。 メインリポジトリのフォークを使用して、手際よく編集しますが、これらの編集はすでにメインリポジトリに含まれているため、メインから取得する方が適切です。 リポジトリはmavenから接続できますが、通常はソースでそのようなものを取得します-すぐに表示、分析の実行、バグの編集をすぐに実行できます-プロジェクトは古くてもかなり粗雑です。



  3. geoipおよびgeoip6-IPアドレスブロックのデータベースを、それぞれIPv4およびIPv6バージョンの各ブロックの地理的位置を参照して更新します。 これを行うには、トーラスのWebサイトからWindows Expertバンドルをダウンロードします。



  4. トーラス自体(つまり、ネイティブライブラリ)を更新します。 標準のパブリックドメインはありません(まあ、または私は見栄えがよくありませんでした)。したがって、Android用のtorおよびtorブラウザを開発している人(OrbotおよびOrfox)に行き、Orbotの最新リリースを取得して、そこからライブラリを取り出します。 そこのトーラスは非常に新鮮で、素晴らしいです。



  5. 私たちの右手で、プロジェクトでコンパイルするのをやめたすべてのもの。 依存ライブラリのいくつかの機能が変更されましたが、一般に、すべてが5分で直観的で修正可能です。



  6. プロジェクトのreadmeの推奨事項に従って、ローカルのMavenリポジトリを作成し、多数の断片からプロジェクトを構築します。 ちなみに、ビルドスクリプトは非常に曲がっているので、1つの場所に以前のリリース自体が含まれていることに注意してください。 ホラー。 そのため、通常のaarライブラリを出力として取得するために、シンプルでわかりやすい言語で再度書き直すことをお勧めします。



ベストプラクティスから収集する方法



ポイント1〜6は既に作成しているので、リポジトリからライブラリを収集するか、リリースセクションでダウンロードします。 リンクは投稿の「地下」にあります。 ただし、コードとライブラリをチェックして、元のコードとライブラリに準拠していること、およびブックマークがないことを確認するのが正しいという事実に注意を促します。 そのようなものを盲目的にアプリケーションに追加しないでください。



心配を止めてトーラスを介してプロキシを開始する方法



まず、トーラスをオンにする必要があります。



int totalSecondsPerTorStartup = 4 * 60; int totalTriesPerTorStartup = 5; try { boolean ok = onionProxyManager.startWithRepeat(totalSecondsPerTorStartup, totalTriesPerTorStartup); if (!ok) Log.e("TorTest", "Couldn't start Tor!"); } catch (InterruptedException | IOException e) { e.printStackTrace(); }
      
      





その後、彼が拾うまで待ちます。



 while (!onionProxyManager.isRunning()) Thread.sleep(90);
      
      





すべてがうまくいった場合-乾杯、彼はいくつかのランダムなポートでローカルホストをリッスンします:



 Log.v("My App", "Tor initialized on port " + onionProxyManager.getIPv4LocalHostSocksPort());
      
      





しかし、それだけではありません。 これで、ポートでSocks4aプロキシとしてリッスンするtorができました。 ただし、すべての標準ライブラリがSocks4aで動作できるわけではありません。 そこでは、匿名性の理由から、ホストのリゾルバがプロキシではなく、より早く発生する必要があります。 どの標準ライブラリがこれを実行できるかわかりません。また、Apache HttpComponentsでコードを記述しました。 なぜそれらを使用できるのかを以前書いたが、この投稿はそれについてではない。 必要に応じて、他のライブラリに同じものを実装できます。



そのため、httpComponentsを使用するには、ConnectionSocketFactoryとSSLConnectionSocketFactoryを書き換える必要があります。



SSLConnectionSocketFactory
 public class MySSLConnectionSocketFactory extends SSLConnectionSocketFactory { public MySSLConnectionSocketFactory(final SSLContext sslContext) { super(sslContext); } @Override public Socket createSocket(final HttpContext context) throws IOException { return new Socket(); } @Override public Socket connectSocket( int connectTimeout, Socket socket, final HttpHost host, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpContext context) throws IOException { Args.notNull(host, "HTTP host"); Args.notNull(remoteAddress, "Remote address"); InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address"); socket = new Socket(); connectTimeout = 100000; socket.setSoTimeout(connectTimeout); socket.connect(new InetSocketAddress(socksaddr.getHostName(), socksaddr.getPort()), connectTimeout); DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); outputStream.write((byte) 0x04); outputStream.write((byte) 0x01); outputStream.writeShort((short) host.getPort()); outputStream.writeInt(0x01); outputStream.write((byte) 0x00); outputStream.write(host.getHostName().getBytes()); outputStream.write((byte) 0x00); DataInputStream inputStream = new DataInputStream(socket.getInputStream()); if (inputStream.readByte() != (byte) 0x00 || inputStream.readByte() != (byte) 0x5a) { throw new IOException("SOCKS4a connect failed"); } else Log.v("SSLConnectionSF", "SOCKS4a connect ok!"); inputStream.readShort(); inputStream.readInt(); SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createLayeredSocket(socket, host.getHostName(), host.getPort(), context); prepareSocket(sslSocket); return sslSocket; } }
      
      







ConnectionSocketFactory
 public class MyConnectionSocketFactory implements ConnectionSocketFactory { @Override public Socket createSocket(final HttpContext context) throws IOException { return new Socket(); } @Override public Socket connectSocket( int connectTimeout, Socket socket, final HttpHost host, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpContext context) throws IOException, ConnectTimeoutException { InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address"); socket = new Socket(); connectTimeout = 100000; socket.setSoTimeout(connectTimeout); socket.connect(new InetSocketAddress(socksaddr.getHostName(), socksaddr.getPort()), connectTimeout); DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream()); outputStream.write((byte) 0x04); outputStream.write((byte) 0x01); outputStream.writeShort((short) host.getPort()); outputStream.writeInt(0x01); outputStream.write((byte) 0x00); outputStream.write(host.getHostName().getBytes()); outputStream.write((byte) 0x00); DataInputStream inputStream = new DataInputStream(socket.getInputStream()); if (inputStream.readByte() != (byte) 0x00 || inputStream.readByte() != (byte) 0x5a) { throw new IOException("SOCKS4a connect failed"); } else Log.v("SSLConnectionSF", "SOCKS4a connect ok!"); inputStream.readShort(); inputStream.readInt(); return socket; } }
      
      







これらの工場の使用は迅速かつ簡単です。 これを行うには、これらのライブラリを使用するHttpClientを作成します。



  public HttpClient getNewHttpClient() { Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", new MyConnectionSocketFactory()) .register("https", new MySSLConnectionSocketFactory(SSLContexts.createSystemDefault())) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg); return HttpClients.custom() .setConnectionManager(cm) .build(); }
      
      





そして、プロキシサーバーに次のように伝えます。



  HttpClient cli = getNewHttpClient(); int port = onionProxyManager.getIPv4LocalHostSocksPort(); InetSocketAddress socksaddr = new InetSocketAddress("127.0.0.1", port); HttpClientContext context = HttpClientContext.create(); context.setAttribute("socks.address", socksaddr);
      
      





これで、通常のクエリを作成しているかのようにトーラスを使用できます。 さらに、.onionウェブサイトにもアクセスできます。



結果



結果のコードをrutrackerのアプリケーションで使用しました。 はい、トーラスの初期化には約20秒かかり、ページの読み込みはそれほど速くありませんが、ロックを渡すことが保証されています。 また、ブロックされていないすべてのリソースは、通常の接続を介してロードされます。 Google Compression Proxyを介して残りのリソースを渡すことは可能ですが、多くの人がこのプロキシがブロックされていると不満を述べました。 もちろん、アプリケーションにはもっと多くの処理が必要な場合があります-たとえば、トラフィックを節約し、作業を高速化するために電話の静的キャッシュを作成します-しかし、これはそれほど重要ではありません。



おわりに



AndroidのThorは非常にうまく機能するクールで便利なものであり、アプリケーションで実際に使用できます。 ところで、はい、これを行うにははるかに簡単な方法があります-Orbotをインストールするだけで、トーラスが上がります。 しかし、一部のアプリケーションが他のアプリケーションに依存することは気に入らず、3 MBの追加はアプリケーションのサイズとしてそれほど重要ではありません。 だから誰かが私の決定を気に入ったら-それを使って、プルリクエストをしてください。



参照:



  1. ソースライブラリ
  2. 私のライブラリビルド ;
  3. rutrackerのアプリケーション
  4. ガーディアンプロジェクト -ネイティブライブラリtorの存在を借りている人たち。









All Articles