- Wireproxy は、WireGuard ピアに接続したうえでローカルマシン上に SOCKS5/HTTP プロキシまたはトンネルとして公開される、完全なユーザー空間の WireGuard クライアント
- 新しいネットワークインターフェイスを設定せずに特定サイトのトラフィックだけを WireGuard ピアへ送りたい場合や、WireGuard 設定変更に root 権限を使いたくない場合を想定している
- 機能には TCP 静的ルーティング、SOCKS5/HTTP プロキシ、TLS SNI ベースの透過プロキシが含まれ、HTTP プロキシは現時点では CONNECT のみをサポート
- 設定は
wg-quick の [Interface]、[Peer] の意味に従い、既存の WireGuard 設定ファイルを WGConfig で取り込んだり、複数ピアを AllowedIPs でルーティングしたりできる
- 運用向けに
--info/-i ベースの health endpoint を提供し、/metrics と /readyz で WireGuard の状態と CheckAlive ベースの準備状態を確認できる
Wireproxy がすること
wireproxy は WireGuard ピアに接続し、ローカルマシンに SOCKS5/HTTP プロキシまたはトンネルを公開するユーザー空間アプリケーション
- 特定サイトだけを WireGuard ピア経由で接続したいが、新しいネットワークインターフェイスは作りたくない場合に利用できる
- ネットワークインターフェイスから完全に分離して動作し、設定のために root 権限は不要
- Amnezia VPN と似た用途が必要なユーザーは、wireproxy-awg フォークを利用できる
対応機能とまだない機能
- 対応機能
- クライアントおよびサーバー向けの TCP 静的ルーティング
- SOCKS5/HTTP プロキシ
- HTTP は現時点では CONNECT のみをサポート
- Server Name Indication を使用する 透過 TLS プロキシ
- TODO として残っている機能
- SOCKS5 の UDP 対応
- UDP 静的ルーティング
実行とインストール
- 基本の実行形式は
./wireproxy [-c path to config]
- 主なオプション
-c, --config: 設定ファイルのパスを指定
- デフォルトパスは
/etc/wireproxy/wireproxy.conf, $HOME/.config/wireproxy.conf
-s, --silent: silent mode
-d, --daemon: バックグラウンド実行
-i, --info: health status 公開用のアドレスとポートを指定
-v, --version: バージョンを出力
-n, --configtest: 設定ファイルの妥当性のみを確認
- ビルドはリポジトリをクローンした後、
make で行う
- インストール例では
go install github.com/windtf/wireproxy/cmd/wireproxy@v1.1.2 または @latest を使用する
設定モデル
[Interface] と [Peer] の設定は wg-quick 設定と同じ意味に従う
Address は IPv4 の場合 /32、IPv6 の場合 /128 サブネットを使用する必要がある
PrivateKey は環境変数参照も可能
- 既存の WireGuard 設定がある場合は
WGConfig = <path to the wireguard config> で取り込める
トンネルとプロキシ設定
TCPClientTunnel
- ローカルマシンで受信した TCP トラフィックを、WireGuard 経由で指定先へ転送する
- 例のフローは
<LAN 앱> → localhost:25565 → WireGuard → play.cubecraft.net:25565
TCPServerTunnel
- WireGuard ネットワークで受信した TCP トラフィックを、ローカルネットワーク上の指定先へ転送する
- 例のフローは
<WireGuard 네트워크 앱> → WireGuard → 172.16.31.2:3422 → localhost:25545
STDIOTunnel
- wireproxy プロセスの標準入力と標準出力を、WireGuard 経由の TCP 宛先に接続する
openssh の ProxyCommand パラメータとして使うのに便利
Socks5
- ローカル LAN に SOCKS5 プロキシを作成し、すべてのトラフィックを WireGuard にルーティングする
- ユーザー名とパスワードを指定すると、プロキシ認証を有効化する
http
- ローカル LAN に HTTP プロキシを作成し、すべてのトラフィックを WireGuard にルーティングする
- ユーザー名とパスワードを指定すると認証を有効化する
CertFile と KeyFile を指定すると HTTPS を有効化する
SNI
- ローカル LAN に透過 TLS プロキシを作成し、SNI をルーティング先として使用して WireGuard 経由でトラフィックを送る
複数ピアとルーティング
- 複数の WireGuard ピアを使用できる
- 複数ピアを使う場合は、wireproxy がどのピアへ転送すべきか分かるように AllowedIPs を指定する必要がある
- 設定例では、異なる
AllowedIPs を持つ複数の [Peer] と複数の TCPServerTunnel を併用する
UDPProxyTunnel の例も含まれる
BindAddress でローカルのバインドアドレスを指定する
Target で対象アドレスを指定する
InactivityTimeout が 0 ならタイムアウトしない
[Resolve] は DNS 解決戦略を設定する
ipv4: A レコードを優先する
ipv6: AAAA レコードを優先する
auto: デフォルト値で、WireGuard インターフェイスが IPv4 アドレスだけを持つ場合は ipv4 と同じ、それ以外は ipv6 と同じ
- Endpoint がない
[Peer] 設定により、ピアが wireproxy に接続することを許可できる
Health endpoint
--info/-i は、たとえば localhost:9080 のようなアドレスとポートを受け取り、health status metric を提供する HTTP サーバーを公開する
- 現在 2 つの endpoint が実装されている
/metrics: WireGuard デーモン情報を公開し、wg show と同じ情報を提供する
/readyz: CheckAlive に指定された IP から最後に pong を受信した時刻を JSON で返す
CheckAlive が設定されている場合、指定アドレスへ CheckAliveInterval 秒ごとに WireGuard 経由で ping を送信する
- デフォルトの
CheckAliveInterval は 5 秒
- 最後の
CheckAliveInterval 秒に遅延猶予 2 秒を加えた時間内に pong を受け取れない場合は 503 を返す
- 条件を満たす場合は 200 を返す
CheckAlive が設定されていない場合、/readyz は空の JSON オブジェクトと 200 を返す
- ICMP ping パケットがルーティングされるピアは、各ピアの AllowedIPs 設定によって変わる
1件のコメント
Hacker News のコメント
小さなツールだが素晴らしい。Firefox の multi-account containers で特定のタブだけを選び、WireGuard はサポートしているがアプリケーション層プロキシや SSH はないホームルーターへプロキシするのに使っている
これを設定するには https://addons.mozilla.org/en-GB/firefox/addon/container-pro... のような別の拡張機能が必要だと思っていたが、そうではなく、今ではそんな勘違いもダウンボートの理由になるようだ
WireGuard でやろうとしていた作業には https://github.com/dariost/soks のほうが合っていた。ほぼ同じことをするが、既存の WireGuard インターフェース を再利用する
使い方はこの記事に詳しく書いた: https://www.nicoco.fr/blog/2023/09/10/wireguard/
ルーティングテーブルを制御手段として使う代わりに、SOCKS5 プロキシを使うかどうかを決める方式のようだ
以前は Raspberry Pi の Docker コンテナで似たようなことをしていたが、どの OS でも動かせて、ホストのルーティングテーブルをうっかり壊さない保証があるので、ユーザー空間の解決策のほうがずっと良い選択に見える
onetun もある: https://github.com/aramperes/onetun
完全な ユーザー空間サーバー実装 もあるのだろうか。tun/tap デバイスなしでやるには、ユーザー空間の IP スタックのようなものが必要そうだが、確信はない
Go でソケット接続に使う Dialer を置き換え、実質的にソケットを WireGuard で包める。ユーザー空間で動作するので tun/tap は不要。これは @dpeckett がすべてオープンソースとして公開している
同じ基盤で DNS 解決まで含むユーザー空間 WireGuard ゲートウェイも作っている: https://github.com/noisysockets/gateway
https://news.ycombinator.com/user?id=dpeckett
私の理解では Google のユーザー空間 TCP/IP スタックを使っている
別の IP が必要なときに使っていた SSH トンネル を置き換えるのに良さそう
関連ツールとして pproxy もあり、多くの機能の一つとして異なるトンネルプロトコル同士を「変換」でき、ルーティング機能もある。SSH SOCKS5 を HTTP プロキシに変えるのに使った: https://github.com/moreati/pproxy
「こういうのは Go ならかなり簡単に作れそうだな」と思ったら、やはり Go で書かれて いた
複数の マルチプロトコルプロキシクライアント がこの機能をサポートしている。代表的なオープンソースの例として sing-box、clash-meta およびその他の clash ベースのクライアント、xray がある
クローズドソースのクライアントでは Surge Mac/iOS がある
あまり知られていないトラフィックルーティングの可能性が多く、Android 実装もある。以前、テザリングをサポートしない SIM と root 化していない Android でテザリングを有効にしようとして使ったことがある
ただ、インターネットのあちこちから持ってきたコードが多く含まれていて、開発者コミュニティもいろいろな理由でかなり独特なので、どれほど信頼できるのかはいつも気になっている
動作の仕組みを深く掘り下げたわけではないが、どのドメインを VPN 経由でプロキシするかをルールグループで決めるという考え方は気に入っている
性能が気になる。記憶では「バニラ」 SOCKS は設定がとても簡単で、つまり SSH を適切なオプションで実行し、アプリケーションにそれを使うよう伝えるだけでよかったが、かなり遅かった
このツールは通常の SOCKS/SSH サーバーがない場合向けのようだが、そちらに対しても利点があるのか気になる
私の場合、SSH 上の SOCKS はいつも性能がかなり良く、OpenSSH の TUN モードのように TCP の上に TCP を重ねる方式とは違っていた
それでもこの解決策にはとても興味がある
Thunderbird のすべてのメール接続を Tailscale exit node 経由でプロキシしつつ、全トラフィックを exit node に送るわけではないツールがあればいいなと、ちょうど考えていたところだった
tailscaleCLI を SOCKS プロキシとして使える: https://tailscale.com/kb/1113/aws-lambdaこれをコンテナイメージに入れて tailscale が待ち受ける SOCKS ポートを公開すれば、そのままプロキシになる
Mullvad VPN 専用にこういうものが必要なら https://github.com/imiric/mullvad-proxy を使ってみて良かった
自分のプロジェクトではなく、更新のためにフォークしただけ。良い点は Mullvad CLI ツールを内蔵していてサーバー切り替えがとても簡単なことと、すべてがホストマシンから隔離されていること。また、「ただの」 nginx といくつかのスクリプトなので SOCKS5 サポートも問題なさそうだ
https://mullvad.net/en/blog/wireguard-configuration-tool-has...