osx で socks proxy の設定を command line で完結させる

# はじめに

osx のネットワーク設定で頻繁に変更する項目などあるでしょうか。わたしの場合、1 つだけあります。それは socks proxy の設定の on/off 切り替えです。とある不自由なネットワーク環境から抜け出るために、ssh の -D オプション (アプリケーションレベルの動的なポートフォワーディング) で外部の自由なネットワークと接続する、というのはわたしに限らず、よくあることではないでしょうか。

しかし osx のネットワーク設定を変更するにあたり、「システム環境設定」の GUI を用いるならまず、「ネットワーク」を選択し、対象となるネットワークサービス (インターフェイス) を選択し、「詳細」ボタンを押し、「プロキシ」タブを開いて、「SOCKS プロキシ」のチェックボックスを ON にし、「SOCKS プロキシサーバ」にある domain、portnumber 等の情報を指定して「OK」ボタンを押し、「適用」ボタンを押す、という操作が必要となります。

設定に必要な情報である domain, portnumber, authenticated, username, password は 1 度だけ指定すればいいにせよ、その他の手順を実行するためにマウスやトラックパッドを操作するのは、いかにも非効率的です。そこで networksetup コマンドです。osx のシステム環境設定で行うことができるネットワークの操作は networksetup コマンドで実行することができます (see networksetup (8))。

networksetup コマンドで指定することができるオプションは実に 100 以上あり、ネットワークの設定変更には admin 権限が必要とマニュアルにはありますが、少なくとも下記で用いるオプションにおいては管理者権限は必要なさそうです。

# ssh -D

socks proxy についてはまたいずれ詳しく正しく書こうと思いますが、ここでは前述の「外部の自由なネットワーク」にあるホストを host1 と表記することにします。なんかいい名前があるといいですね。「約束の地」とかを意味する単語とか。

ssh の -D オプションは前述の通り、アプリケーションレベルの動的なポートフォワーディングで、SOCKS4 か SOCKS5 プロトコルがサポートされています。ssh (1) のマニュアルにはこのように書かれています。

> -D [bind_address:]port
Specifies a local ``dynamic'' application-level port forwarding.  This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address.  Whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine.  Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server.  Only root can forward privileged ports.  Dynamic port forwardings can also be specified in the configuration file.

> IPv6 addresses can be specified by enclosing the address in square brackets.  Only the superuser can forward privileged ports.  By default, the local port is bound in accordance with the GatewayPorts setting.  However, an explicit bind_address may be used to bind the connection to a specific address.  The bind_address of ``localhost'' indicates that the listening port be bound for local use only, while an empty address or `*' indicates that the port should be available from all interfaces.

-D オプションの後には bind_address と port を : で挟んで指定しますが、bind_address は省略可能です。省略した場合、あるいは * を指定した場合は全てのネットワークインターフェイスから、この動的なポートフォワーディングサービスを利用することができます。localhost を指定するとローカルホストからしか利用することができません。本稿のような利用形態においてはセキュリティの観点から bind_address には localhost を指定しておくべきなのかもしれません。ポート番号はなぜだか 10080 がよく用いられておりますので、ここでも 10080 としておきます。その理由についてもいつか調べておきたいところです。

```shell
% ssh -D localhost:10080 host1
```

# networksetup

## listallnetworkservices

host1 とのセッションが確立した状態で、ローカルホストで networksetup コマンドを実行します。まずは socks proxy の対象となる networkservice の名前を調べます。networkservice とは、osx のシステム環境設定のネットワークの画面において、左側ペインに表示されているインターフェイスなどのことを意味します。デフォルトでは物理インターフェイス (Ethernet や Wi-Fi) が表示されているだけですが、VLAN や VPN、6to4 などで用いられる仮想インターフェイスも含まれるので、これらを包括して networkservice と呼んでいるものと思われます。

```shell
% networksetup -listallnetworkservices
An asterisk (*) denotes that a network service is disabled.
Ethernet
Wi-Fi
```

オプション -listallnetworkservices により全ての networkservice が表示されます。ssh で host1 とセッションを確立したとき、どの networkservice を利用しているのかを調べる手段は…これは一意に定めることができない気がするので明記を避けておきます。各々の環境に応じて、どの networkservice を使って host1 とのセッションが確立されているかを確認しておきます。

## setsocksfirewallproxy

次に networksetup コマンドで socks proxy の設定を行います。これは ssh -D で指定したローカルホストの情報を反映させますので、ssh -D でどこに接続するにせよ、ローカルホストでの bind_address や port の指定はいつも同じという運用にするならば、一度設定すれば二度三度設定する必要はありません。socks proxy の設定は -setsocksfirewallproxy オプションを指定します。networksetup (8) によると

> __-setsocksfirewallproxy__ networkservice domain portnumber authenticated username password
> Set SOCKS Firewall proxy for <networkservice> with <domain> and <port number>. Turns proxy on. Optionally, specify <on> or <off> for <authenticated> to enable and disable authenticated proxy support. Specify <username> and <password> if you turn authenticated proxy support on.

とのことで、システム環境設定で設定できる SOCKS プロキシの全ての情報を networkservice でも指定できることがわかります。先ほど示したような ssh -D でのセッション確立においては、domain (bind_address)、portnumber のみを指定すればよく、authenticated、username、password は指定する必要がありません。

```shell
% networksetup -setsocksfirewallproxy Ethernet localhost 10080
```

## getsocksfirewallproxy

正しく設定が行われたかどうかは -getsocksfirewallproxy オプションを指定することで確認することができます。

>__-getsocksfirewallproxy__ networkservice
>Displays SOCKS Firewall proxy (server, port, enabled value) info for <networkservice>.

とのことなので、-getsocksfirewallproxy のあとに networkservice を指定します。

```shell
% networksetup -getsocksfirewallproxy Ethernet
Enabled: No
Server: localhost
Port: 10080
Authenticated Proxy Enabled: 0
```

出力を見てみると、Enabled: が No になっていることがわかります。設定を投入しただけでは SOCKS プロキシは On になりません。システム環境設定での設定もそうですね。

## setsocksfirewallproxystate

設定した SOCKS プロキシの設定の有効化は getsocksfirewallproxy で行います。

> __-setsocksfirewallproxystate__ networkservice on | off
> Set SOCKS Firewall proxy to  either <on> or <off>.

```shell
% networksetup -setsocksfirewallproxystate Ethernet on
```

SOCKS プロキシの利用を終了したら、off にしておきましょう。

```shell
% networksetup -setsocksfirewallproxystate Ethernet off
```