このリポジトリには、他のネットワーク プロトコルを介して TCP および UDP トラフィックをトンネルできるようにするクライアントとサーバーが含まれています。
現在サポートされているトンネルは次のとおりです。
メインツールは Rust で書かれ、エンドツーエンドのテストは Python で書かれています。
docker pull ghcr.io/dlemel8/tunneler-server:latest
docker pull ghcr.io/dlemel8/tunneler-client:latest
cargo --version || curl --proto ' =https ' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release
ローカルの docker イメージを構築したい場合は、docker ファイルもあります
docker run -e LOCAL_PORT=45301
-e REMOTE_PORT=5201
-e REMOTE_ADDRESS=localhost
-e TUNNELED_TYPE=udp
--rm -p 45301:45301 ghcr.io/dlemel8/tunneler-server:latest tcp
./target/release/client
--tunneled-type tcp
--remote-address 1.1.1.1
--remote-port 53
--log-level debug
dns
--read-timeout-in-milliseconds 100
--idle-client-timeout-in-milliseconds 30000
詳細については、 --help
を指定して docker イメージまたはコンパイルされたバイナリを実行してください
cargo test --all-targets
python3 -m pip install -r e2e_tests/requirements.txt
PYTHONPATH=. python3 -m pytest -v
このリポジトリには、Docker Compose を使用したサーバー デプロイメントの例がいくつか含まれています。
各サンプルはローカルで実行することも、Terraform と Ansible を使用してデプロイすることもできます。詳細については、こちらをご覧ください。
各実行可能ファイルには、クライアント ストリームのチャネル (バイト リーダーとライターのタプル) を介して通信する 2 つのコンポーネントが含まれています。
TCP ベースのトラフィックは簡単にストリームに変換されます。 UDP ベースのトラフィック変換は、トンネル プロトコルに依存します。
UDP ベースのトラフィックには、セッションを継続するために既存のクライアントを識別する方法も必要です。この解決策は、クライアントの識別子をそのストリームにマップするメモリ内のクライアント キャッシュです。
UDP トラフィックをストリームに変換するために、2 バイト サイズのヘッダー (ビッグ エンディアン) が各パケット ペイロードの前に置かれます。
UDP リスナーは、受信パケットのピア アドレスをクライアント キャッシュのキーとして使用します。
ここにはいくつかの課題があります。
これらの課題を解決するために、各クライアント セッションはランダムなクライアント ID (4 つの英数字) を生成することから始まります。クライアントはデータを読み取ってトンネリングし、エンコーダーのパイプライン経由で実行します。
エンコードされたデータは、TXT DNS クエリの名前として使用されます。
権威 DNS サーバーを所有している場合、クライアントは再帰 DNS リゾルバーにリクエストを送信できます。リゾルバーはドメイン名レジストラーから IP を取得し、リクエストを IP に転送します。もう 1 つのオプション (より高速ですが、トラフィック アナライザにとってより明白です) は、要求を IP (ポート UDP/53 またはサーバーがリッスンしている他のポート) に直接送信するようにクライアントを構成することです。
サーバーはデータをデコードし (クライアント以外のトラフィックは無視します)、クライアント ID をクライアント キャッシュのキーとして使用します。
大きなサーバー応答と空の TCP ACK を処理するために、クライアントとサーバーの両方で読み取りタイムアウトが使用されます。読み取りタイムアウトが経過すると、空のメッセージが送信されます。クライアントとサーバーの両方がアイドル タイムアウトを使用して、転送を停止し、ローカル リソースをクリーンアップします。
相互認証を実装するには、プライベート認証局を使用します。
クライアントとサーバーは両方とも、TLS ハンドシェイクでキーと証明書を使用するように構成されています。 CA 証明書はルート証明書として使用されます。
Server Name Indication 拡張機能が使用されているため、クライアントは特定のサーバー名を要求し、サーバーはその名前が要求された場合にのみ証明書を提供します。サーバー名も、たとえばサブジェクトの代替名として証明書の一部である必要があります。