#背景
macOSだとプロキシ必須の環境ではうまく動かないソフトウエアがいくつかあります。例えば、KindleとかMicrosoft OneNoteとかがシステムのプロキシ設定を読み込んでくれず、うまく使えません。そのほかに.bashrc
にも環境変数をセットしたり、Dockerや仮想マシンを立ち上げるたびに環境変数をセットしてまわったりとかなり手間がかかります。このような時に便利なのが透過型プロキシで「NAT をやめて、透過 SOCKS プロキシを導入した」や「プロキシとの戦いに疲れたのでgoで透過プロキシを作ってみた」でiptablesを利用したLinux向けの実装が紹介されています。しかし、新しいネットワークを切りたくはないし、それだけのためにLinuxの仮想マシンを用意したくもなかったので、macOSやFreeBSDで採用されているpfを用いてローカルで動く透過プロキシを構成してみました。
#実装方法
実装は「プロキシとの戦いに疲れたのでgoで透過プロキシを作ってみた」で紹介されていたgo-transproxy
からiptablesを無効化できるようにしたバージョンを利用します。~~そのうち本家にマージされるかもしれませんが、私のリポジトリにおいてあります。~~→マージされました。また、iptablesの代わりにpfを用いており、さらにルーティングされるパケットではなく出ていくパケットを全部捕まえるので、ネットワークを分けることなく手元のマシンから出ていくパケットをすべてプロキシ経由にできます。
#使い方
- go-transproxyリポジトリから最新版のソースコードをダウンロードし、ビルドする。
- http_proxy, https_proxy, no_proxy(IPアドレスのみ対応可能)をセットする
-
./transproxy -disable-iptables
でgo-transproxyを立ち上げる(sudo不要) - 以下の内容のpf.confを適当なディレクトリに作成する。
- もとに戻すためにも/etc/pf.confではない方がよいでしょう。
-
{!192.168.0.0/16}
の部分はno_proxyに設定した範囲と正確に逆転させた範囲を指定します。- 範囲が一つだけなら!が使えますが、複数ある場合にはとても面倒で、間違えると通信がループします。
-
em0
となっている2か所は適切な外部接続インターフェース書き換えます。macOSならen0
かもしれません。
Packets = "proto tcp from em0 to {!192.168.0.0/16}"
rdr pass log on lo0 $Packets port 80 -> 127.0.0.1 port 3129
rdr pass log on lo0 $Packets port 443 -> 127.0.0.1 port 3130
pass out on em0 route-to lo0 inet $Packets port {80, 443} keep state
-
sudo pfctl -f ./pf.conf
で作成したFirewallルールをロードする。 - private DNS, public DNSを指定して、DNS Proxy機能も使いたい場合にはシステムのDNSをlocalhostに設定する。
- 終了するときには
sudo pfctl -f /etc/pf.conf
で元のルールをロードする。
ヘルパーツール
no_proxyの設定やpfの設定ファイルを作成して読み込むためのヘルパーツールを作成して、gistにおいておきました。Python3が必要ですが、同じディレクトリにtransproxy
を置いておけば環境変数のセットやpfのロード、アンロードを自動的に行います。
#注意点
制限事項として以下のことがあります。
- macOSのアプリケーションファイアウォールとは共存できません。
- 原因はわかりませんがmacOSのファイアウォールのanchorと共存できないので、外部接続を行うノートPCでは別途設定を行っておいた方が良いでしょう。
- たぶん同様の理由でネットワーク共有とも共存できない気がします。
- 誰か解決出来たら教えてください。
- ホスト名でのプロキシ除外はできません
-
go-transproxy
の本来の想定であるルーターでの透過型プロキシでなく、ローカルから出ていく通信のすべてを透過型プロキシ経由にするので、pfのIPアドレスで除外設定をしておかないと通信がループします。そのため、あらかじめIPアドレスのわからないホスト名での除外はできません。- うまくプロセス単位の設定ができれば解決しますが、誰か教えてください。
- ユーザー単位での除外もできるので、
go-transproxy
だけ別ユーザーで動かして、除外しておけば対応可能です。
-
- pfのルールを書くのにOpenBSDのドキュメントを参照してはなりません
- FreeBSDやmacOSのpfはバージョンが古く、syntaxが違います。
#参考