Macで任意のアプリケーションをSOCKSプロキシ経由にしてみたかったので試してみた

2020.05.23

Macでは「ネットワーク環境設定 > Wi-Fi > 詳細 >プロキシ」でSOCKSプロキシ設定が可能です。一方で、この設定だと基本的にMacのネットワーク設定を参照するアプリケーションには全てプロキシが適用されます。(ターミナル上でのsshやcurlなどのCLIアプリケーションやGoogle Chromeなど、適用されないものもある)

そこで今回は「任意のアプリケーションのみに適用することはできるか?」ということが気になったので色々と試してみました。

前提条件

OSはMacを利用しており、バージョンは 10.15.4 です。 また、プロキシ経由での接続検証としては、DB接続クライアントであるDBeaverを利用し、プロキシ経由でしか繋がらないDBへ接続テストをすることで検証としました。

試したもの

今回は以下を試してみました。

  • Proxifier(有償)
  • Proximac(オープンソース)
  • tsocks(オープンソース)

最初に結論!

最初に結論を書くと、試した限りでは「Proxifier」のみが期待通りの動作をしてくれました。

1. Proxifier

ProxifierはMac、Windows共にサポートしているプロキシクライアントです。HTTPS、SOCKS(v4, v5)に対応しており、Ruleを設定することで任意のアプリケーションを任意のプロキシ経由で接続させることができます。

ダウンロードとインストール

公式サイトから、ダウンロードしてインストールします。今回は「31-day Free Trial」でお試しをしました。

使い方

基本的な使い方としては、以下のようになります。

Proxiesの設定

まずは、プロキシサーバの設定を行います。Proxiesボタンをクリックしてプロファイルダイアログを表示させます。

Add...ボタンをクリックしてプロキシ設定ダイアログを表示させます。

AddressPortに接続するプロキシサーバのアドレスとポートを、Protocolにプロキシサーバのプロトコルの指定をしてOKをクリックします。

「このプロキシをProxifierがデフォルトで利用するようにしますか?」と聞かれるのでNoにします。

これでプロキシサーバの設定ができました。

Rulesの設定

次に、プロキシを適用するルールを設定します。Rulesボタンをクリックしてプロファイルダイアログを表示させると、デフォルトでは すべて直接接続になっていることが分かります。 Add...ボタンをクリックしてルール設定ダイアログを表示させます。

Nameに適宜名前を入力します。「前提条件」で書いた通り、今回はDBeaverで試したいのでDBeaverとしました。名前を入れたら、Applicationsの箇所の+ボタンをクリックしてアプリケーションを指定します。

アプリケーションの選択ダイアログが表示されるのでDBeaverを指定してOpenをクリックします。

すると、アプリケーションがネットワーク接続で利用するモジュールも自動で検出して、追加するか聞いてくれるのでYesをクリックします。

最後にActionに先程設定したプロキシサーバを指定してOKをクリックします。

これで、指定したアプリケーションだけプロキシサーバを経由する設定になりました。(プロファイルダイアログは閉じて大丈夫です)

DBeaverで検証

では、DBeaverを起動して検証してみます。プロキシサーバ経由でしか接続できないDB接続を事前に設定しているので、「接続設定 > テスト接続」から試してみます。

接続できました!

Proxifierのログからも、ちゃんとハンドリングしてプロキシサーバ経由接続になっていることが分かります。

検証は以上です。期待通りに動いてくれていますね。

2. Proximac

Proximacはオープンソースで公開されているコマンドラインベースのProxifier代替ソフトです。対応OSは名前からも分かるようにMacOSのみとなっています。

インストールと利用方法

GitHubリポジトリのREADME.mdにおけるUsageに従ってインストールと実行を行います。

インストール、のその前に...

最初のステップが、なにやら面倒そうなので、改めてこの手順で何を行うのか確認しておきます。

「リカバリモードで csrutil enable --without kext --without debug を実行」という旨が記載されていますが、これは何を意味しているのでしょうか?

まず、MacOSですがEl CapitanからSystem Integrity Protection (SIP)というシステムファイルの書き換えを保護する仕組みが導入されているとのことです。これにより、セキュリティを高めているということですね。

csrutilコマンドはこのSIPの設定を変更するコマンドになるそうです。更に、オプションの--without kext --without debugは何を意味しているのでしょうか?

これは、下記サイトを参照させて頂いたところ、--without kextで「未署名のカーネル拡張モジュールを許可」するようになる、と分かりました。

セキュリティに影響を及ぼす変更となるので、設定する際にはその旨を理解した上で設定すると良いですね。

1. System Integrity Protection (SIP)の設定変更

では、設定変更を進めます。

まず最初にREADME.mdに記載のOSX 10.10+に当てはまるかな?と思い、以下のコマンドを実行してみましたがエラーになりました。

$ sudo nvram boot-args="debug=0x146 kext-dev-mode=1"
nvram: Error setting variable - 'boot-args': (iokit/common) not permitted

これがまさに上記のSIPの制約によるものなので、「復元モード」での対応が必要でした。「復元モード」の起動の仕方は下記の公式ドキュメントに記載の通りです。

OS起動後に、ロゴが出るまでCommand + Rを押して「復元モード」で起動します。起動すると言語選択画面が表示されるので「日本語」を選択して、次に進みます。

「パスワードが分かっているユーザーを選択」と出たら、選択して次に進むと「macOSユーティリティ」が起動します。

ここまで来たら画面上部のメニューバーが表示されているので「ユーティリティ > ターミナル」からターミナルを起動し、コマンドを実行してSIPの設定を変更します。

# csrutil enable --without kext --without debug
csrutil: requesting an supported configuration. This is likely to break in the future and leave your machine in an unknown state.
csrutil: requesting an supported configuration. This is likely to break in the future and leave your machine in an unknown state.
Successfully enabled System Integrity Protection. Please restart machine for the changes to take effect.

設定変更が成功し再起動するように促されるので、メニューバーの「Appleロゴ > 再起動」から再起動をします。

再起動が終わったら、ターミナルからSIPの状態を確認します。

$ csrutil status
System Integrity Protection status: unknown (Custom Configuration).

Configuration:
	Apple Internal: disabled
	Kext Signing: disabled
	Filesystem Protections: enabled
	Debugging Restrictions: disabled
	DTrace Restrictions: enabled
	NVRAM Protections: enabled
	BaseSystem Verification: enabled

This is an unsupported configuration, likely to break in the future and leave your machine in an unknown state.

Kext SigningDebugging Restrictionsdisabledになっており、想定通り設定変更されていそうですね。

2. libuvのインストール

これは単純にbrewでインストールすればOKですね。

$ brew install libuv
(略)
==> Downloading https://homebrew.bintray.com/bottles/libuv-1.37.0.catalina.bottle.tar.gz
==> Downloading from https://akamai.bintray.com/d4/d4e33db48819f466b6b1391242f95f1e61ccd0e27418693610a5eeec20633350?__gd
######################################################################## 100.0%
==> Pouring libuv-1.37.0.catalina.bottle.tar.gz
🍺  /usr/local/Cellar/libuv/1.37.0: 48 files, 3MB

3. proximacのインストール

ここで、ようやく本体をインストールします。

$ curl -fsSL https://raw.githubusercontent.com/proximac-org/proximac-install/master/install.py |sudo python
Password:
Resources has been downloaded!
Now change kernel extension's owner
Please enter your password to obtain root priviledge
Proximac is successfully installed!
To uninstall, just delete these files:
/usr/local/proximac/* (root)
/usr/local/bin/proximac

これで完了です。

4. configファイルの設定

README.mdのサンプルにあるようにconfigファイルを作成します。

process_nameに、プロキシサーバ経由にしたいアプリケーションを、local_addresslocal_portに利用したいSOCKSプロキシサーバのアドレスとポートを指定してみます。proximac_portは不明ですが、そのままにしておくようにREADMEに記載があるのでそのままとします。

Leave proximac_port alone because this is now hardcoded in kext source.

~/.proximac.conf

{
    "process_name":
    ["dbeaver"],
    "local_port":1080,
    "local_address":"proxy.sample.com",
    "proximac_port":8558,
}

5. proximacの実行

configファイルを作成したら、下記のコマンドで実行してみます。

$ proximac start -c ~/.proximac.conf
Password:
 2020-05-21 13:45:21 INFO: Process List:
 2020-05-21 13:45:21 INFO: 1. dbeaver hash -38524903
 2020-05-21 13:45:21 INFO: Hook Succeed!
 2020-05-21 13:45:21 INFO: The total number of process that will be hooked = 1
 2020-05-21 13:45:21 INFO: Listening on 8558

実行できているように見えます。

DBeaverで検証

では、DBeaverを起動して検証してみます。先程と同様に「接続設定 > テスト接続」から試してみます。

接続できません…。タイムアウトしました。

config設定に問題があるのかなと思い、プロセス名にProxifierが自動検出してくれたプロセス名を入れたり、プロキシサーバへの接続をローカルにして、プロキシサーバとローカルをsocatで繋げてみたりしましたが、改善しませんでした。

$ socat tcp4-listen:1080,reuseaddr,fork TCP:proxy.sample.com:1080

~/.proximac.conf

{
    "process_name":
    ["dbeaver","java","jcmd","jinfo","jmap","jps","jrunscript","jspawnhelper","jstack","jstat","keytool","pack200","rmid","rmiregistry","unpack200"],
    "local_port":1080,
    "local_address":"127.0.0.1",
    "proximac_port":8558,
}

また、別途以下のconf設定にしてcurlを対象として検証をしてみました。

~/.proximac.conf

{
    "process_name":
    ["curl"],
    "local_port":1080,
    "local_address":"127.0.0.1",
    "proximac_port":8558,
}
$ curl inet-ip.info
xxx.xxx.xxx.xxx ← proxy経由で想定されるGlobal IP

これは、問題なく想定通りの動きですね。以上の試行錯誤により、以下の結果が分かりました。

  • process_nameでアプリケーションを指定しても想定通りに動かないアプリもある
  • local_addressにはリモートのプロキシサーバ指定はできない
  • curlは動いた
    • CLIアプリケーションだけうまくいく可能性がある

目的としてはMacのGUIアプリケーションを動かしたかったのですが、今回の検証ではうまくいきませんでした。もし情報をお持ちの方がいたら教えて頂けると喜びます!

3. tsocks

tsocksもオープンソースで公開されているコマンドラインベースで透過的にプロキシ経由でネットワーク接続を行うソフトです。

インストールと利用方法

公式には上記のようにSourceForgeで公開されていますが、有志でGitHubにもいくつかリポジトリが公開されているようです。 私は以下のリポジトリを参考にインストールを行いました。brewによるインストールもいくつか見つけましたが、うまく動かないようなので最終的にはソースコードからmakeをすることにしました。

1. tsocksのインストール

GitHubリポジトリのtsocks/INSTALL.osxに従ってインストールを行います。まずは記載されている手順通り以下を実行します。

$ autoconf
$ ./configure --prefix=/usr
$ make
$ sudo make install
/bin/sh mkinstalldirs  "/usr/bin"
/usr/bin/install -c tsocks /usr/bin
install: /usr/bin/tsocks: Operation not permitted
make: *** [installscript] Error 71

すると、インストール途中でエラーになりました。このエラーはSIPによる書き込みエラーです。下記の記事を参考にさせて頂き、Proximacでの実施と同様にリカバリモードでOSを起動し直して、一旦オフにしました。

# csrutil disable
Successfully disabled System Integrity Protection. Please restart machine for the changes to take effect.

再起動したら、SIPがオフになっているか確認します。

$ csrutil status
System Integrity Protection status: disabled.

オフになっていますね。更に、書き込みをさせるには下記のようにマウントし直す必要があるとのことなのでマウントし直します。

$ sudo mount -uw /

では、再度インストールします。

$ sudo make install
Password:
/bin/sh mkinstalldirs  "/usr/bin"
/usr/bin/install -c tsocks /usr/bin
/bin/sh mkinstalldirs  "/usr/lib"
/usr/bin/install -c libtsocks.dylib.1.8 /usr/lib
ln -sf libtsocks.dylib.1.8 /usr/lib/libtsocks.dylib.1
ln -sf libtsocks.dylib.1 /usr/lib/libtsocks.dylib
/bin/sh mkinstalldirs  "/usr/share/man/man1"
/usr/bin/install -c -m 644 tsocks.1 /usr/share/man/man1/
/bin/sh mkinstalldirs  "/usr/share/man/man8"
/usr/bin/install -c -m 644 tsocks.8 /usr/share/man/man8/
/bin/sh mkinstalldirs  "/usr/share/man/man5"
/usr/bin/install -c -m 644 tsocks.conf.5 /usr/share/man/man5/

無事、インストールできました!あとは/usr/bin/tsocksに記載されているLIBDIR/usr/libに変更して完了です。

$ sudo vim /usr/bin/tsocks

/usr/bin/tsocks

(~略~)
LIBDIR=/usr/lib
(~略~)

2. confファイルの設定

confファイルは以下のように作成します。ファイルパスは/etc/tsocks.confです。

/etc/tsocks.conf

server = 127.0.0.1
server_type = 5
server_port = 1080

3. tsocksの実行

confファイルを作成したら実行してみます。使い方はシェルで実行ファイルの前にtsocksを指定するだけです。

まずはsocatを利用して、ローカルの1080への通信をリモートのプロキシサーバへ転送するようにします。

$ socat tcp4-listen:1080,reuseaddr,fork TCP:proxy.sample.com:1080

これで127.0.0.1:1080proxy.sample.com:1080に飛ぶようになったので、下記のコマンドで試してみます。

$ tsocks /Applications/DBeaver.app/Contents/MacOS/dbeaver

が、こちらもproximacと同様にダメでした。また、試しにcurlで試したところ、こちらはproximacと同様に成功しました。

$ tsocks curl inet-ip.info
xxx.xxx.xxx.xxx ← proxy経由で想定されるGlobal IP

まとめ

以上、Macで任意のアプリケーションをSOCKSプロキシ経由にしてみようと試してみた結果でした!

今回、できればProximacやtsocksでうまく任意のアプリケーションをSOCKSプロキシ経由で動かしたかったのですが、試した限りではProxifierが断然良い感じに動くことが分かりました。

どなたかのお役に立てば幸いです。それでは!