Help us understand the problem. What is going on with this article?

Macでプロキシとの戦いに疲れたので、透過型プロキシを導入してみた

More than 1 year has passed since last update.

背景

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が違います。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした