[22] [DFN[[[SOCKS]]]] は、 [[TCP]] [[アプリケーション]]のための[[トンネル]]化[[プロトコル]]です。
[[防火壁]]等を越えて [[HTTP]] その他の[[アプリケーション層プロトコル]]で通信するために使います。

[54] [[SOCKS]] は [[TCP]] の上位層、[[アプリケーション層プロトコル]]の下位層として動作します。

* 仕様書

[REFS[
- [9] [CITE[SOCKS: A protocol for TCP proxy across firewalls]] ([TIME[2002-04-03 17:26:00 +09:00]] 版) <http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol>
- [14] [CITE[SOCKS 4A: A  Simple Extension to SOCKS 4 Protocol]] ([TIME[2012-04-12 19:29:58 +09:00]] 版) <http://www.openssh.com/txt/socks4a.protocol>
- [6] [CITE@en[RFC 1928 - SOCKS Protocol Version 5]] ([TIME[2015-08-02 14:17:13 +09:00]] 版) <https://tools.ietf.org/html/rfc1928>
- [7] [CITE[RFC Errata Report]] ([TIME[2015-09-11 18:57:28 +09:00]] 版) <https://www.rfc-editor.org/errata_search.php?rfc=1928>
- [76] [CITE[Service Name and Transport Protocol Port Number Registry]] ([TIME[2015-09-17 07:18:22 +09:00]] 版) <https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=socks>
- [75] [CITE[SOCKS Methods]] ([TIME[2014-01-31 02:45:14 +09:00]] 版) <https://www.iana.org/assignments/socks-methods/socks-methods.xhtml>
]REFS]

* 版

[67] [[SOCKS]] には 4、4A、5 の3つの版があります。

[68] 最初に普及したのが 4 で、それに[[ドメイン名]]対応を追加したのが 4A
です。

[69] [[IETF]] で改めて作られたのが 5 です。

[70] [[サーバー]]は 4/4A と 5 のいずれであるかを受信内容
(先頭1バイト) から区別できます。
4 と 4A のいずれであるかも実用上は区別できます。つまり[[サーバー]]はすべての版を同時に実装可能です。

[71] [[クライアント]]は 4、4A、5 のいずれを使うべきか事前の知識なく決めることができません。
この意味で版間の互換性がありません。

;; [72] [[IETF]] ではよくあることですが、 [[IETF]] 
の[[専門家]]好みのスタイルに[[プロトコル]]が改造された結果互換性が無くなり、
旧版から新版への移行が進まず、かといって新版が無視されるわけでもなく、
新旧両版が十数年以上も併用され続けています。

[163] [[クライアント]]は[[利用者]]にどの版を使うか指定させる必要があります。
[[SOCKS]] に対応した[[ライブラリー]]の類は、3つの版のいずれかを指定する方法を提供しているのが普通です。
[[Firefox]] の設定画面では 4 と 5 のいずれかを指定できます。
[[PAC]] (>>73) は、 4 と 5 のいずれかを指定できます。

;; [164] [[Firefox]] の設定画面では、 5 を選んだ場合のみ、更に[[名前解決]]して
[[IPアドレス]]を使うか、[[ドメイン名]]をそのまま使うか指定できます。
[[PAC]] で [CODE[SOCKS5]] と指定した時は、[[ドメイン名]]をそのまま使うようです。
[TIME[2015-09-22T10:18:07.300Z]]

[165] [[Chrome]] は 4 が選ばれた場合に 4 と 4A のどちらを使うかを次のように決めています
[SRC[>>66]]。
[FIG(steps)[
= [166] [[名前解決]]に成功したら、
== [167] 結果が[[IPv4アドレス]]なら、 4 を使います。
== [168] 結果が[[IPv6アドレス]]なら、 4A を使います。
= [169] [[名前解決]]に失敗したら、 4A を使います。
]FIG]

;; [173] が実際ためしてみると[[名前解決]]に成功して [[IPv4アドレス]]を得た場合以外[[名前解決]]失敗で[[ネットワークエラー]]になっているように見えます。 [TIME[2015-09-22T06:46:14.000Z]]

[170] [[Firefox]] は[[名前解決]]に成功して [[IPv4アドレス]]を得たら 4 
を使い、それ以外では[[ネットワークエラー]]とするようにみえます。 [TIME[2015-09-22T05:17:25.900Z]]

[174] [[Chrome]] も [[Firefox]] も[[名前解決]]結果が [[IPv4アドレス]]
[CODE[[[0.0.0.0]]/8]] だったら、[[名前解決]]に失敗したとして[[ネットワークエラー]]にするようです。
これを [[SOCKS]]4 で送信することはありませんから、 4A とサーバーに誤認されることはありません。
[TIME[2015-09-22T07:10:09.300Z]]

;; [185] [[Windows]] の [[Chrome]] で [CODE[0.0.0.0]] 自体に接続しようとすると、
ERR_ADDRESS_INVALID エラーとなります ([CODE[127.0.0.1]] で[[サーバー]]が動作していても、
エラーになります)。その他の [CODE[[[0.0.0.0]]/8]]
に接続しようとすると、 ERR_ADDRESS_UNREACHABLE エラーとなります。
[CODE[[[0.0.0.0]]/8]]  に解決される名前に接続しようとすると、
ERR_NAME_NOT_RESOLVED エラーとなります ([[名前解決]]できない時と同じエラーです)。
[TIME[2016-09-23T03:01:04.00Z]]

[FIG(table)[
[FIGCAPTION[
[140] [[SOCKS]] プロトコルの版の比較
]FIGCAPTION]

:v:版
:ipv4:[[IPv4]]
:ipv6:[[IPv6]]
:domain:[[ドメイン名]]
:auth:[[認証]]方式
:tcp:[[TCP]]
:udp:[[UDP]]

:v:4
:ipv4:○
:ipv6:×
:domain:×
:auth:名前
:tcp:○
:udp:×

:v:4A
:ipv4:○
:ipv6:×
:domain:○
:auth:名前
:tcp:○
:udp:×

:v:5
:ipv4:○
:ipv6:○
:domain:○
:auth:認証なし、[[GSSAPI]]、[[名前]]と[[合言葉]]
:tcp:○
:udp:○

]FIG]

* 端点

[141] [[SOCKS]] プロトコルの通信には、次の3種類のものが関わります。

[142] [[クライアント]]は、 [[SOCKS]] プロトコルの通信を開始します。
[[クライアント]]は [[SOCKS]] プロトコルを通じて他の
(普通は[[防火壁]]の向こう側にあって [[SOCKS]] がないとアクセスできない)
アプリケーションサービスを利用しようとするものです。

[143] [[サーバー]]は、 [[SOCKS]] プロトコルの通信を受け付けます。
[[SOCKS]] [[クライアント]]との接続が確立されると、
[[クライアント]]が通信したい相手 ([[アプリケーションサーバー]]) 
との [[TCP]] 通信を中継することになります。

[144] [[UDP]] 中継サーバーは、 [[SOCKS]]5 [CODE[[[UDP ASSOCIATE]]]]
により確立され、[[クライアント]]と[[クライアント]]が通信したい相手
([[アプリケーションサーバー]]) との [[UDP]] 通信を中継することになります。

* プロトコル

[147] [[SOCKS]] は[[クライアント]]が[[サーバー]]に接続して、
その[[サーバー]]を介して他の[[サーバー]] ([[アプリケーションサーバー]])
に接続するものです。 [[SOCKS]] [[サーバー]]は[[防火壁]]であることが主として想定されていますが、
それに限られるわけではありません。いずれにせよ、[[クライアント]]が直接[[アプリケーションサーバー]]に接続するのではなく、
[[SOCKS]] [[サーバー]]を[[プロキシ]]として利用して通信するものです。

[148] [[SOCKS]] では [[TCP]] や [[UDP]] の通信を扱うことができます。
[[HTTPプロキシ]]のように[[アプリケーション層プロトコル]]の通信を解釈することなく、
透過的に[[クライアント]]と[[アプリケーションサーバー]]との間の[[通信路]]として機能しますから、
[[アプリケーション層プロトコル]]側で特別な対応は必要ありません。

[146] [[下位層]]として基本的には [[TCP]] を使います。 [CODE[[[UDP ASSOCIATE]]]]
では [[UDP]] も使います。

[149] [[SOCKS]] プロトコル上の[[パケット]]単位は「[RUBYB[[[メッセージ]]]@en[message]]」
と呼ばれています。[[クライアント]]から[[サーバー]]への指示の[[メッセージ]]のことを[RUBYB[[[要求]]]@en[request]]、
[[サーバー]]から[[クライアント]]への返答の[[メッセージ]]のことを[RUBYB[返信]@en[reply]]といいます。

;; [150] ただし [[SOCKS]] としての初期化が終わった後は[[アプリケーション]]層のデータをそのまま送受信するモードになりますから、
[[SOCKS]] プロトコルの[[メッセージ]]とはなりません。

[19] [[SOCKS]] 4 には [CODE[[[CONNECT]]]] と [CODE[[[BIND]]]] の2つの[RUBYB[操作]@en[operation]]があります [SRC[>>9]]。

[139] [[SOCKS]] 5 には [CODE[[[CONNECT]]]] と [CODE[[[BIND]]]] と
[CODE[[[UDP ASSOCIATE]]]] の3つの[RUBYB[命令]@en[command]]があります。

[151] [[SOCKS]] 4 では操作と認証を同じメッセージでまとめて行います。
[CODE[[[CONNECT]]]] の場合、一往復で [[SOCKS]] としての必要手続きは完了します。

[152] [[SOCKS]] 5 では版と認証方式の折衝、認証、命令の3段階があり、
最低 ([[認証]]なし) でも二往復しないといけません。

[160] [[SOCKS]] 4 も [[SOCKS]] 5 も、時代背景や[[標準化団体]]が [[IETF]] 
であることから、仕様書の規定はあまり明瞭ではなく、通信相手が仕様に反する場合の扱いも定かではありません。

* SOCKS 4 / 4A

[21] [[要求]]には次の欄があります。

[FIG(list members)[
:[CODE[[[VN]]]]: 最初のバイトはプロトコルの版番号で、 [CODE[4]] とするべきです [SRC[>>9]]。
:[CODE[[[CD]]]]: 第2バイトは[RUBYB[命令符号]@en[command code]]で、
[CODE[[[CONNECT]]]] では [CODE[1]] とするべきで、
[CODE[[[BIND]]]] では [CODE[2]] としなければなりません [SRC[>>9]]。
:[CODE[[[DSTPORT]]]]: その次の2バイト [SRC[>>9]] は[[ポート番号]]です。
:[CODE[[[DSTIP]]]]: その次の4バイト [SRC[>>9]] は[[IPアドレス]]です。
:[CODE[[[USERID]]]]: その次の任意の長さのバイト列は userid とします [SRC[>>9]]。
:[CODE[[[NULL]]]]: 最後の1バイトは [CODE[0]] とします [SRC[>>9]]。
:[[ドメイン名]]: [[SOCKS]] 4A では、更に任意の長さの[[ドメイン名]]を含められる場合があります [SRC[>>14]]。
:[CODE[[[NULL]]]]: [[ドメイン名]]がある場合、その次の1バイトは [CODE[0]] とします [SRC[>>14]]。
]FIG]

[FIG(packet)[
:width:32

= 8 VN
= 8 CD
= 16 DSTPORT
= 32 DSTIP
= 56... USERID
= 8 NULL
= 56... ドメイン名
= 8 NULL
]FIG]

[32] 明記されていませんが、 [CODE[[[USERID]]]] や[[ドメイン名]]に [[NULL]]
は含められないと思われます。 [CODE[[[USERID]]]] や[[ドメイン名]]を空 (長さ0)
にすることも禁止はされていません。

[49] [[SOCKS]] 4 では、 USERID の後の NULL までで終わりでした。
[[SOCKS]] 4A では、 [CODE[[[DSTIP]]]] の先頭3バイトをすべて [CODE[0]]、
最終バイトを非 [CODE[0]] とすることで、[[ドメイン名]]とその終端の [[NULL]] 
を使うことができます [SRC[>>14]]。

[50] [CODE[[[DSTIP]]]] の先頭3バイトが [CODE[0]]、最終バイトが非 [CODE[0]]
の時、 [[IPアドレス]]ではなく、[[ドメイン名]]の指定によることを表します [SRC[>>14]]。

;; [51] 明記されていませんが、[[ドメイン名]]は [CODE[.]] で区切られた[[ラベル]]の列と思われます。
時代的に [[ASCII]] のみの[[ドメイン名]]が期待されていると思われますが、
[[非ASCII文字]]をどう扱うべきなのかは定かではありません。

;; [52] 0.0.0.* の * は 0 以外のどの値にしても良いようですが、
その選択に意味はなさそうです。

[172] [[Chrome]] も [[Firefox]] も[[認証]]には対応しておらず、
[CODE[userid]] は常に空とするようです。 [TIME[2015-09-22T06:40:54.600Z]]

[37] 返答パケットには次の欄があります [SRC[>>9]]。

[FIG(list members)[
:[[VN]]: 最初の1バイトは、返答符号の版とします。 [CODE[[[0]]]] とするべきです [SRC[>>9]]。
:[[CD]]: 次の1バイトは、結果符号とします [SRC[>>9]]。
:[CODE[[[DSTPORT]]]]: その次の2バイト [SRC[>>9]] は[[ポート番号]]です。
:[CODE[[[DSTIP]]]]: その次の4バイト [SRC[>>9]] は[[IPアドレス]]です。
]FIG]

[FIG(packet)[
:width:32

= 8 VN
= 8 CD
= 16 DSTPORT
= 32 DSTIP
]FIG]

[26] 結果符号は、次のいずれかです [SRC[>>9]]。
[FIG(list)[
- [N[90[SUB[10]]][90]] は、要求を受け入れたことを表します。
- [N[91[SUB[10]]][91]] は、要求を拒絶または失敗したことを表します。
- [N[92[SUB[10]]][92]] は、[[クライアント]]の [[identd]] に接続できなかったために要求を拒絶したことを表します。
- [N[93[SUB[10]]][93]] は、[[クライアント]]と [[identd]] が異なる user-id を報告したために要求を拒絶したことを表します。
]FIG]

[48] 明記されていませんが、[[ネットワークバイト順]]と思われます。

[53] [CODE[[[VN]]]] や [CODE[[[CD]]]] が未知の値や想定外の文脈だった時にどう扱うべきかは定かではありません。

** [CODE[CONNECT]] 操作

[20] [[クライアント]]は、他のホストに接続したい時、 [[SOCKS]] [[サーバー]]に接続して、
[CODE[[[CONNECT]]]] [[要求]]を送信します [SRC[>>9]]。

[31] [CODE[[[DSTIP]]]] は[[終点]]の [[IPアドレス]]
(または[[ドメイン名]]の指定があることを表す値 [SRC[>>14]])、
[CODE[[[DSTPORT]]]] は[[終点]]の[[ポート番号]]とします [SRC[>>9]]。

[23] [[サーバー]]は、 [CODE[[[CONNECT]]]] [[要求]]を受信したら、
受け付けるかどうかを次の情報の一部または全部を使って検査します [SRC[>>9]]。
[FIG(list)[
- [[始点]] [[IPアドレス]]
- [[終点]] [[IPアドレス]]
- [[終点]][[ポート番号]]
- [[userid]]
- [[RFC 1413]] [[IDENT]] により得られる情報
]FIG]

[24] [[サーバー]]は、要求を受け付ける場合には、
指定された[[終点]]のホストとポートに接続します [SRC[>>9]]。

[25] [[サーバー]]は、接続が確立されたら、
または拒絶する時や操作が失敗した時は、
返答パケットを送信します [SRC[>>9]]。

[38] 返答パケットの [CODE[[[DSTIP]]]] と [CODE[[[DSTPORT]]]] は、無視します [SRC[>>9]]。

;; [39] サーバーが何を設定するべきなのかは明らかではありません。

[27] [[サーバー]]は失敗または拒絶を通知したら、直ちに[[接続]]を閉じます [SRC[>>9]]。

[45] 一定時間 (例えば2分) 経過後接続が確立できていなければ、
断念して[[クライアント]]との接続も閉じます [SRC[>>9]]。

;; [46] その場合も返答パケットは送信するべきと思われますが、不明瞭です。

[171] [[Chrome]] も [[Firefox]] も、正しい結果 [CODE[90]] の返答でなければ、
[[TCP]] [[接続]]を閉じて[[ネットワークエラー]]とするようです。 [TIME[2015-09-22T06:39:40.100Z]]

[176] [[Chrome]] も [[Firefox]] も、要求への返答全体を受信するまで、
その内容の評価を行わないようです。 [TIME[2015-09-22T07:41:01.800Z]]

[177] [[Chrome]] も [[Firefox]] も、仕様通り返答中の [[IPアドレス]]と[[ポート番号]]を無視するようです。 [TIME[2015-09-22T07:41:25.400Z]]

[175] 要求後 [[Chrome]] は 30s、 [[Firefox]] は 90s、
返答がなければ[[タイムアウト]]とするようです。 [TIME[2015-09-22T07:16:56.600Z]]

[28] 要求を受け入れた場合は、以後送受信を中継します [SRC[>>9]]。

** [CODE[BIND]] 操作

[29] [[クライアント]]は、他のホストからの接続を受け付けたい時、
[[SOCKS]] [[サーバー]]に接続して [CODE[[[BIND]]]]
要求を送信します [SRC[>>9]]。

;; [30] 任意のホストに対するアプリケーションサービスの提供を想定しているのではなく、
[CODE[[[CONNECT]]]] で主たる接続を確立済みの同じアプリケーションでサーバーからクライアントへと補助的な接続を確立する
(のを待ち受ける) ためのもののようです。

[33] [CODE[[[DSTIP]]]] はアプリケーションサーバーの [[IPアドレス]]
(または[[ドメイン名]]の指定があることを表す値 [SRC[>>14]])、
[CODE[[[DSTPORT]]]] は主たる接続の[[ポート番号]]とします [SRC[>>9]]。

;; [34] つまり [CODE[[[CONNECT]]]] 要求で指定した[[終点]]です。

[35] [[サーバー]]は、[[クライアント]]の情報により、
受け付けるかどうか決定します [SRC[>>9]]。

[36] [[サーバー]]は、受け付ける場合も受け付けない場合も、
返答パケットを送信します [SRC[>>9]]。

[40] 受け入れる場合 ([CODE[[[CD]]]] = [CODE[[[90]]]]) は、
[[サーバー]]は接続を待ち受けることとし、その[[IPアドレス]]と[[ポート番号]]を返答パケットの 
[CODE[[[DSTIP]]]] と [CODE[[[DSTPORT]]]] にそれぞれ設定します [SRC[>>9]]。

[41] [CODE[[[DSTIP]]]] が [CODE[[[0]]]] ([CODE[[[INADDR_ANY]]]])
の場合、[[クライアント]]は、[[SOCKS]] [[サーバー]]の
[[IPアドレス]]とみなすべきです [SRC[>>9]]。

[42] それ以外の場合は [CODE[[[DSTIP]]]] と [CODE[[[DSTPORT]]]] は無視されます [SRC[>>9]]。

[43] [[サーバー]]が待ち受けるアドレスに接続があると、
次のようにします。
[FIG(steps)[
= 接続元の[[ホスト]]と [CODE[[[BIND]]]] 要求の [CODE[[[DSTIP]]]] が一致すれば、
== 返答パケットを[[クライアント]]に送信します。 [CODE[[[CD]]]] は [CODE[[[90]]]] とします。
== 以後両接続間の送受信を中継します。
= それ以外なら、
== 返答パケットを[[クライアント]]に送信します。 [CODE[[[CD]]]] は [CODE[[[91]]]] とします。
== 両接続とも、切断します。
]FIG]

[44] 一定時間 (例えば2分) 経過後接続が確立できていなければ、
断念して[[クライアント]]との接続も閉じます [SRC[>>9]]。

;; [47] その場合も返答パケットは送信するべきかもしれませんが、不明瞭です。

* SOCKS 5

** 認証方式

[153] [[SOCKS]] 5 では最初に[[クライアント]]と[[サーバー]]の間で[[認証方式]]を折衝し、
それに応じて[[認証]]します。

[154] 更に[[認証]]後の[[メッセージ]]その他の送受信におけるデータのカプセル化の方法は[[認証方式]]によって規定できます。
例えば[[認証方式]]によっては暗号化や署名の方法と構文を規定できます。

[99] 方式識別子 ([CODE[METHOD]]) には次の値があります。
[FIG(list)[
,* [CODE[METHOD]],* 意味
,* [CODE[0x00]] , 認証不要 [SRC[>>6]]
,* [CODE[0x01]] , [[GSSAPI]] [SRC[>>6]]
,* [CODE[0x02]] , USERNAME/PASSWORD [SRC[>>6]]
,* [CODE[0x03]] , Challenge-Handshake Authentication Protocol [SRC[>>75]]
,* [CODE[0x05]] , Challenge-Response Authentication Method [SRC[>>75]]
,* [CODE[0x06]] , [[SSL]] [SRC[>>75]]
,* [CODE[0x07]] , NDS Authentication [SRC[>>75]]
,* [CODE[0x08]] , Multi-Authentication Framework [SRC[>>75]]
,* [CODE[0x80]]-[CODE[0xFE]] , 私的な方式に予約 [SRC[>>6]]
,* [CODE[0xFF]] , 認められる方式なし [SRC[>>6]]
]FIG]

[101] [CODE[METHOD]] の開発者は、 [[IANA登録簿]]に登録するべきです [SRC[>>6]]。

[102] [[GSSAPI]] を実装しなければ[['''なりません''']] [SRC[>>6]]。

[103] USERNAME/PASSWORD を実装する[['''べきです''']] [SRC[>>6]]。

[156] [CODE[0x03]]-[CODE[0x7F]] は[[IANA登録簿]] [SRC[>>75]] の登録対象 [SRC[>>6]]
とされています。

[155] 実際幾つかの認証方式が開発され、 [[IANA登録簿]] [SRC[>>75]] に登録されています。
実装も存在していたようです。しかしいずれも [[I-D]] のまま放置されています。

[158] [[Webブラウザー]]は、認証方式なし ([CODE[0x00]]) にしか対応していないようです。
現在の [[SOCKS]] の利用の多くは同一環境で動作している [[SOCKSプロキシ]]を使うものでしょうから、
[[認証]]は不要なのだと思われます。認証に対応するよう要望が出されてもいますが、
長年未対応のままで、それほど需要は大きくないようです。

;; つまり [[RFC]] の規定は実態に合っていません。

[REFS[
- [8] [CITE@en[RFC 1929 - Username/Password Authentication for SOCKS V5]] ([TIME[2015-07-26 16:21:40 +09:00]] 版) <https://tools.ietf.org/html/rfc1929>
- [10] [CITE@en[RFC 1961 - GSS-API Authentication Method for SOCKS Version 5]] ([TIME[2015-06-21 17:56:54 +09:00]] 版) <https://tools.ietf.org/html/rfc1961>
- [12] [CITE@en[draft-ietf-aft-socks-chap-01 - Challenge-Handshake Authentication Protocol for SOCKS V5]] ([TIME[2015-07-20 00:36:46 +09:00]] 版) <https://tools.ietf.org/html/draft-ietf-aft-socks-chap-01>
- [79] [CITE@en[draft-ietf-aft-socks-cram-00 - Challenge-Response Authentication Method for SOCKS V5]]
([TIME[2015-07-23 13:33:45 +09:00]] 版)
<https://tools.ietf.org/html/draft-ietf-aft-socks-cram-00>
- [80] [CITE@en[draft-ietf-aft-socks-ssl-00 - Secure Sockets Layer for SOCKS Version 5]]
([TIME[2015-07-20 17:44:24 +09:00]] 版)
<https://tools.ietf.org/html/draft-ietf-aft-socks-ssl-00>
- [81] [CITE@en[draft-ietf-aft-socks-maf-01 - Multi-Authentication Framework Method for SOCKS V5]]
([TIME[2015-07-20 17:49:20 +09:00]] 版)
<https://tools.ietf.org/html/draft-ietf-aft-socks-maf-01>
]REFS]

** アドレス型

[107] [CODE[ATYP]] 欄は、 [CODE[DST.ADDR]] 欄や [CODE[BND.ADDR]]
欄の[[アドレス]]の種別を表すものです [SRC[>>6]]。

[108] 次の値があります。

[FIG(table)[
:value:値
:length:アドレス欄の長さ
:desc:アドレス欄の値

:value:[CODE[0x01]] [SRC[>>6]]
:desc:[[IPv4アドレス]]
:length:4バイト

:value:[CODE[0x03]] [SRC[>>6]]
:desc:バイト数 (1バイト) と、そのバイト数の [[FQDN]]

:value:[CODE[0x04]] [SRC[>>6]]
:desc:[[IPv6アドレス]]
:length:16バイト

]FIG]

[159] [[FQDN]] は、時代的に [[IDN]] が考慮されておらず、どう扱われるのかは定かではありません。
また[[末尾の点]]の扱いも明確ではありません。更に [[FQDN]] と規定されてはいますが、
実際には[[サーバー]]の[[名前解決]]の実装に依存する可能性もあります。

** プロトコル

[88] [[TCP]] による接続は、[[クライアント]]から次のようにします。
[FIG(steps)[
= [89] [[TCP]] で [[SOCKS]] [[サーバー]]に接続します [SRC[>>6]]。
= [84] [RUBYB[版識別子・方式選択メッセージ]@en[version identifier/method selection message]]を送信します [SRC[>>6]]。
[FIG(list members)[
:VER: 1バイト。 [CODE[5]]。 [SRC[>>6]]
:NMETHODS: 1バイト。 [CODE[METHODS]] に含まれる方式識別子オクテットの数。 [SRC[>>6]]
:METHODS: 1-255バイト。 [SRC[>>6]] [[クライアント]]が受け入れる[[認証方式]]のリストを表す方式識別子オクテットの列。
]FIG]
]FIG]

[94] [[サーバー]]は、これを受けて、
[FIG(steps)[
= [96] 受信した [CODE[METHODS]] からいずれか1つを選びます [SRC[>>6]]。
適切なものがなければ [SRC[>>6]]、 [CODE[0xFF]] とします。
= [95] 次のような [RUBYB[METHOD 選択メッセージ]@en[METHOD selection message]]を送信します [SRC[>>6]]。
[FIG(list members)[
:VER: 1バイト。 [SRC[>>6]] [CODE[5]]。
:METHOD: 1バイト。 [SRC[>>6]] 選択した方式識別子。
]FIG]
]FIG]

[97] そして[[クライアント]]は、
[FIG(steps)[
= [98] [CODE[METHOD]] が [CODE[0xFF]] なら、接続を閉じなければなりません [SRC[>>6]]。
ここで停止します。
]FIG]

[100] その後、[[クライアント]]と[[サーバー]]の間で方式依存の折衝を行います [SRC[>>6]]。

[157] 認証方式が [CODE[0x00]] の場合は、何もしないと思われます。

[179] [[Chrome]] も [[Firefox]] も、最初に受信した2バイトが [CODE[0x0500]]
でなければ [[TCP]] 接続を閉じます。(2バイトを受信するまで待ちます。) [TIME[2015-09-22T09:43:24.800Z]]

[104] それが済んだら、[[クライアント]]は、
[FIG(steps)[
= [105] 要求を作成します。
[FIG(list members)[
:VER: 1バイト。 [CODE[5]]。 [SRC[>>6]]
:CMD: 1バイト。 [CODE[CONNECT]] = [CODE[1]], [CODE[BIND]] = [CODE[2]],
[CODE[UDP ASSOCIATE]] = [CODE[3]] のいずれか。 [SRC[>>6]]
:RSV: 1バイト。 [CODE[0x00]]。 [SRC[>>6]]
:ATYP: 1バイト。 [CODE[DST.ADDR]] のアドレス型。 [SRC[>>6]]
:DST.ADDR: [CODE[ATYP]] 依存の長さ。望む[[終点]]アドレス。 [SRC[>>6]]
:DST.PORT: 2バイト。望む[[終点]][[ポート]]。[[ネットワークバイト順]]。 [SRC[>>6]]
]FIG]
= [86] ([[一貫性]]の検査や[[機密性]]のため) 折衝方式依存のカプセル化が規定されているなら、
カプセル化しなければ[['''なりません''']] [SRC[>>6]]。
= [106] 要求を送信します。
]FIG]

[87] それに対して[[サーバー]]は、普通は[[始点]]と[[終点]]の[[アドレス]]を評価して、
適切な[[接続]]を確立して[[要求]]の種類に応じた[[メッセージ]]を返すか、
または拒絶します [SRC[>>6]]。

[109] [[サーバー]]は、次のように[RUBYB[返答]@en[reply]]します。
[FIG(steps)[
= [110] 次のような返答メッセージを作成します [SRC[>>6]]。
[FIG(list members)[
:VER: 1バイト。 [CODE[5]]。 [SRC[>>6]]
:REP: 1バイト。返答。 [SRC[>>6]]
:RSV: 1バイト。 [CODE[0x00]] でなければなりません。 [SRC[>>6]]
:ATYP: 1バイト。 [CODE[BND.ADDR]] のアドレス型。 [SRC[>>6]]
:BND.ADDR: サーバーが束縛したアドレス。 [SRC[>>6]]
:BND.PORT: 2バイト。サーバーが束縛した[[ポート]]。[[ネットワークバイト順]]。 [SRC[>>6]]
]FIG]
= [111] ([[一貫性]]の検査や[[機密性]]のため) 折衝方式依存のカプセル化が規定されているなら、
カプセル化します [SRC[>>6]]。
= [112] 返答を送信します。
]FIG]

[113] [CODE[REP]] 欄には、次の値を使います [SRC[>>6]]。
[FIG(list)[
- [CODE[0x00]] - 成功
- [CODE[0x01]] - 一般的な [[SOCKS]] サーバーの失敗
- [CODE[0x02]] - 規則集合により接続が認められていない
- [CODE[0x03]] - ネットワーク到達不能
- [CODE[0x04]] - ホスト到達不能
- [CODE[0x05]] - 接続が拒絶された
- [CODE[0x06]] - [[TTL]] [[満期]]
- [CODE[0x07]] - 命令に対応していない
- [CODE[0x08]] - アドレス型に対応していない
- [CODE[0x09]]-[CODE[0xFF]] - 未割当
]FIG]

[123] 返答が失敗の時 ([CODE[[[REP]]]] ≠ [CODE[[[0x00]]]])、
[[サーバー]]は[[返答]]の送信のすぐ後に [[TCP接続]]を閉じなければ[['''なりません''']]。
これは失敗検出の後10s[[以下]]でなければなりません。 [SRC[>>6]]

[124] 返答が成功の時 ([CODE[[[REP]]]] = [CODE[[[0x00]]]]) で[[要求]]が
[CODE[[[BIND]]]] や [CODE[[[CONNECT]]]] なら、
[[クライアント]]はデータを送信できるようになります [SRC[>>6]]。
[[サーバー]]は受信したデータを[[クライアント]]に送信します。

[125] [[認証方式]]が規定する場合は、[[クライアント]]や[[サーバー]]は送信するデータを適当にカプセル化しなければ[['''なりません''']]
[SRC[>>6]]。

[178] [[Chrome]] も [[Firefox]] も、 [CODE[[[BND.ADDR]]]] の第1バイトまで読み込んでから、
そこまでの各バイトを評価して、問題があればエラーとして [[TCP]] 接続を閉じます。
[TIME[2015-09-22T09:37:11.000Z]]

[180] 返答待ちのタイムアウトは [[Chrome]] は30s、 [[Firefox]] は90sのようです。
[TIME[2015-09-22T09:51:36.600Z]]

[186] [[サーバー]]や[[クライアント]]は相手のメッセージの受信をまたずに自身のメッセージ
(や確立後の [[TCP]] データ) を送信できてしまいます。そのような場合に受信者がこれをどう処理するべきかは不明です。

** [CODE[CONNECT]] 要求

[114] [CODE[[[CONNECT]]]] [[要求]]に対する返答の場合、
[CODE[[[BND.PORT]]]] は[[サーバー]]が対象ホストへの接続に割り当てた[[ポート番号]]、
[CODE[[[BND.ADDR]]]] は関連付けられた [[IPアドレス]]です [SRC[>>6]]。

[116] [CODE[[[BIND]]]] [[要求]]は、[[サーバー]]からの[[接続]]を受け付ける必要がある時に使います 。
[CODE[[[CONNECT]]]] [[要求]]により確立された主たる[[接続]]の後に二次的な接続を確立するために使うことを想定しています。
[CODE[[[BIND]]]] [[要求]]の評価には[[要求]]の [CODE[DST.ADDR]]
と [CODE[DST.PORT]] っを使うことが想定されています。 [SRC[>>6]]

[181] [[Chrome]] でも [[Firefox]] でも、 [CODE[[[BND.ADDR]]]] と
[CODE[[[BND.PORT]]]] は無視されます。しかし何らかの適切な [CODE[ATYP]]
と [CODE[ATYP]] に応じだ [CODE[[[BND.ADDR]]]] を指定しなければエラーになります。
[TIME[2015-09-22T10:05:00.500Z]]

** [CODE[BIND]] 要求

[115] [CODE[[[BIND]]]] [[要求]]によって[[サーバー]]が新しい[[ソケット]]を作成、
[[束縛]]したら、[[クライアント]]に最初の返答を送信します。
ここでは、 [CODE[[[BND.PORT]]]] に接続を待つべく [[listen]]
するよう割り当てた[[ポート番号]]を、
[CODE[[[BND.ADDR]]]] には関連付けられた[[IPアドレス]]を指定します。 [SRC[>>6]]

[117] その後当該[[ソケット]]への[[接続]]が成功または失敗したら、
次の返答を送信します。
[CODE[[[BND.PORT]]]] と [CODE[[[BND.ADDR]]]]
は、接続してきたホストの[[ポート番号]]と[[アドレス]]とします。 [SRC[>>6]]

** [CODE[UDP ASSOCIATE]] 要求

[118] [CODE[[[UDP ASSOCIATE]]]] [[要求]]は、
[[UDP]] [[データグラム]]の中継を確立するものです。 [SRC[>>6]]

[119] [[要求]]の [CODE[[[DST.ADDR]]]] と [CODE[[[DST.PORT]]]]
は、[[クライアント]]が [[UDP]] [[データグラム]]を送信したい[[アドレス]]と[[ポート]]です。
[[クライアント]]が [CODE[[[UDP ASSOCIATION]]]] [[要求]]の送信時点で決定できないときは、
[[ポート番号]] [CODE[[[0]]]] を使わなければ[['''なりません''']]。
[SRC[>>6]]

[120] [[サーバー]]は、 [CODE[[[UDP ASSOCIATE]]]] [[要求]]の
[CODE[[[DST.ADDR]]]] や [CODE[[[DST.PORT]]]] に基づきアクセスを制限できます。
[SRC[>>6]]

[121] [CODE[[[UDP ASSOCIATE]]]] [[要求]]による [[UDP]] との関連付けは、
当該 [[TCP接続]]が終了した時に終了します。 [SRC[>>6]]

[122] [CODE[[[UDP ASSOCIATE]]]] [[要求]]への返答では、
[CODE[[[BND.PORT]]]] と [CODE[[[BND.ADDR]]]]
には(中継されることとなる) [[UDP]] の宛先として[[クライアント]]が使うべき[[ポート番号]]と[[アドレス]]を指定します。
[SRC[>>6]]

[129] [[UDP]] を使う[[クライアント]]は、
[CODE[[[UDP ASSOCIATE]]]] [[要求]]に対する返答の [[UDP]] 中継サーバーの
[CODE[[[BND.PORT]]]] で指定された [[UDP]] [[ポート]]に対して[[データグラム]]を送信しなければ[['''なりません''']] [SRC[>>6]]。

[130] [[認証方式]]が規定する場合は、[[データグラム]]を適当にカプセル化しなければ[['''なりません''']]
[SRC[>>6]]。

[131] 各 [[UDP]] [[データグラム]]には、 [RUBYB[UDP要求ヘッダー]@en[UDP request header]]を付します。
[[UDP要求ヘッダー]]は次の欄で構成されます。 [SRC[>>6]]
[FIG(list members)[
:RSV: 2バイト。 [CODE[0x0000]]。 [SRC[>>6]]
:FRAG: 1バイト。現在素片番号。 [SRC[>>6]]
:ATVP:1バイト。 [CODE[DST.ADDR]] のアドレス型。 [SRC[>>6]]
:DST.ADDR: 可変長。望む[[終点]]アドレス。 [SRC[>>6]]
:DST.PORT: 2バイト。望む[[終点]]ポート。 [SRC[>>6]]
:DATA: 可変長。[[利用者]]データ。 [SRC[>>6]]
]FIG]

;; [145] 「[[ヘッダー]]」とは言っていますが、 [CODE[DATA]] 欄が含まれるのですから、
その前までが[[ヘッダー]]、全体としては[[メッセージ]]と呼ぶべきものでしょう。

[132] [[UDP]] 中継サーバーは、 [[UDP]] [[データグラム]]を中継することにした場合は、
そうします。中継しないまたはできない場合は、単に無視します。 [SRC[>>6]]

[133] [[UDP]] 中継サーバーが遠隔ホストから返答[[データグラム]]を受信したら、
[[UDP]] 要求ヘッダーと認証方式依存の方法でカプセル化しなければ[['''なりません''']]。
[SRC[>>6]]

[134] [[UDP]] 中継サーバーは、[CODE[[[UDP ASSOCIATE]]]]
[[要求]]への返答の [CODE[[[BND.PORT]]]] で示された[[ポート]]に[[データグラム]]を送ることになる[[クライアント]]の想定
[[IPアドレス]]を [[SOCKS]] [[サーバー]]から得なければ[['''なりません''']]。
それ以外の[[始点]] [[IPアドレス]]からの[[データグラム]]を無視しなければ[['''なりません''']]。
[SRC[>>6]]

[135] [CODE[[[FRAG]]]] 欄は、当該[[データグラム]]が[[素片]] ([[断片]])
群の1つを構成するかどうかを表します。
[CODE[0x00]] は単独の[[データグラム]]を表します。
[[最上位ビット]]が最後の[[素片]]を表します。
下位7ビットが[[素片]]の列における位置を表します。
[SRC[>>6]]

[136] 受信者は素片について [CODE[REASSEMBLY QUEUE]] と
[CODE[REASSEMBLY TIMER]] を持ちます。[CODE[REASSEMBLY TIMER]]
は5s[[未満]]であっては[['''なりません''']]。 [CODE[REASSEMBLY TIMER]]
が[[満期]]になったり、これまでの最高の [CODE[FRAG]] 値よりも小さな
[CODE[FRAG]] 値の[[データグラム]]を受信したりしたら、
[CODE[REASSEMBLY QUEUE]] を最初期化しなければなりません。 [SRC[>>6]]

[137] [[アプリケーション]]は、可能な限り[[素片]]化 ([[断片化]]) を避けるべきです。
[[素片]]化を実装する必要はありません。未対応の実装が [CODE[FRAG]]
値 [CODE[0x00]] 以外の[[データグラム]]を受信したら、
無視しなければ[['''なりません''']]。 [SRC[>>6]]

[138] [[SOCKS]] 対応 [[UDP]] の [[API]] は、 [[OS]]
が提供する[[バッファー]]の最大サイズよりも次のバイト数だけ小さな値を利用可能なサイズとして報告しなければ[['''なりません''']]。
[SRC[>>6]]

[FIG(list)[
- [CODE[ATYP]] が 0x01 なら、 10 + 認証方式依存の長さ [SRC[>>6]]
- [CODE[ATYP]] が 0x03 なら、 262 + 認証方式依存の長さ [SRC[>>6]]
- [CODE[ATYP]] が 0x04 なら、 22 + 認証方式依存の長さ [SRC[>>7]]
]FIG]

* 下位層プロトコル

[161] 下位層プロトコルとして [[TCP]] や一部 [[UDP]] を使いますが、
その方法は明確ではありません。

[162] 例えば[[緊急ポインター]]が指定されている時どう扱うべきなのか、
[CODE[[[RST]]]] を受信したらどうするべきなのかなど明確な規定はありません。

;; [[緊急データ]]は無視するべきなのか、それとも透過的に扱い[[アプリケーション]]に委ねるべきなのか、など。

* ポート番号

[85] [[SOCKS]]5 では、普通は [CODE[[[1080]]]] 番[[ポート]]を使います [SRC[>>6]]。

[77] [[TCP]] と [[UDP]] の[[ポート番号]] [DFN[[CODE[[[1080]]]]]] は[[サービス]]
[DFN[[CODE[[[socks]]]]]] として [[IANA登録簿]]に登録されています。
説明は「Socks」となっています。 [SRC[>>76]]

;; [78] 明らかに [[SOCKS]] のことを指しているのでしょうが、
[[IANA登録簿]]には明記されていません。

* URL scheme

[74] [[プロキシ]]の指定などで [[URL]] を指定する時に、次の [[URL scheme]]
が用いられます。

[FIG(short list)[
- [CODE(URI)@en[[[socks:]]]]
- [CODE(URI)@en[[[socks4:]]]]
- [CODE(URI)@en[[[socks4a:]]]]
- [CODE(URI)@en[[[socks5:]]]]
- [CODE(URI)@en[[[socks5h:]]]]
]FIG]

* PAC

[73] [[PAC]] では次の値が [[SOCKSプロキシ]]を表すために使われています。
[FIG(short list)[
- [CODE@en[[[SOCKS]]]]
- [CODE@en[[[SOCKS4]]]]
- [CODE@en[[[SOCKS5]]]]
]FIG]

[182] [CODE[SOCKS]] は、 [[SOCKS4]] を表します [SRC[>>61]]。

* 実装

[128] [[SOCKS]] の[[サーバー]]と[[クライアント]]の実装として、
[[Dante]] があります。

[127] [[Webブラウザー]]をはじめ、多くの[[インターネット]][[アプリケーション]]の[[クライアント]]プログラムやライブラリーが
[[SOCKS]] [[クライアント]]機能を持っています。

[126] [[socksify]] ([[dante]]) や [[tsocks]] のような、 [[SOCKS]] を実装していないプログラムの
[[TCP/IP]] 接続部分を [[SOCKS]] 利用に差し替えるプログラムもあります。

[FIG[
[FIGCAPTION[
[1] [CITE[AnyEvent::HTTP::Socks - search.cpan.org]] ([TIME[2012-04-25 09:51:27 +09:00]] 版) <http://search.cpan.org/~oleg/AnyEvent-HTTP-Socks-0.04/lib/AnyEvent/HTTP/Socks.pm>
]FIGCAPTION]

[PRE(URI code)[
  "socks4://10.0.0.1:1080  socks5://root:123@10.0.0.2:1080  socks4a://85.224.100.1:9010"
]PRE]
]FIG]

[FIG[
[FIGCAPTION[
[3] [CITE[AnyEvent::HTTP::Socks - search.cpan.org]] ([TIME[2012-04-25 09:51:27 +09:00]] 版) <http://search.cpan.org/~oleg/AnyEvent-HTTP-Socks-0.04/lib/AnyEvent/HTTP/Socks.pm>
]FIGCAPTION]

[PRE(URI code)[
  http_get 'http://www.google.com/', socks => 'socks5://localhost:1080', sub {
]PRE]
]FIG]

[4] [CITE[LWP::Protocol::socks - search.cpan.org]]
([TIME[2010-01-20 18:01:04 +09:00]] 版)
<http://search.cpan.org/~scr/LWP-Protocol-socks-1.1/lib/LWP/Protocol/socks.pm>

[FIG[
[FIGCAPTION[
[5] [CITE[SSH: プロキシ設定の定義]] ([TIME[2011-12-14 03:32:52 +09:00]] 版) <http://www.ssh.com/manuals/client-user/43J/firewall.html>
]FIGCAPTION]

> プロキシサーバのアドレスを入力します SOCKSプロキシのためのアドレス形式は次のとおりです。
[PRE(URI code)[
socks://username@socks_server:port/network/netmask,network/netmask...
]PRE]
>
プロキシサーバ設定の例: 
[PRE(URI code)[
socks://socks.ssh.com:1080/203.123.0.0/16,198.74.23.0/24
]PRE]
]FIG]

* メモ

[2] [CITE@ja[SOCKS - Wikipedia]]
( ([TIME[2011-12-10 16:21:00 +09:00]] 版))
<http://ja.wikipedia.org/wiki/SOCKS>

[13] [CITE@en[SOCKS - Wikipedia, the free encyclopedia]] ([TIME[2015-09-05 01:05:46 +09:00]] 版) <https://en.wikipedia.org/wiki/SOCKS>

[11] [CITE@en[RFC 3089 - A SOCKS-based IPv6/IPv4 Gateway Mechanism]] ([TIME[2015-07-26 16:11:34 +09:00]] 版) <https://tools.ietf.org/html/rfc3089>

[15] [CITE[IO::Socket::Socks - search.cpan.org]]
([TIME[2015-09-11 19:05:59 +09:00]] 版)
<http://search.cpan.org/dist/IO-Socket-Socks/lib/IO/Socket/Socks.pm>

[16] [CITE@ja[第 15 章 SOCKS の使用]]
([TIME[2010-12-30 01:42:14 +09:00]] 版)
<https://docs.oracle.com/cd/E19438-01/819-3160/agsocks.html>

[17] [CITE@en[Socks Proxy - Free Socks5 and Socks4 Proxy List]]
([TIME[2015-09-11 19:32:04 +09:00]] 版)
<http://www.socks-proxy.net/>

[18] >>17 によれば 5 が多いですが、 4 (4 か 4a かは不明。) もまだまだ使われているようです。
[TIME[2015-09-11T10:11:54.200Z]]

[FIG(quote)[
[FIGCAPTION[
[55] [CITE[cURL - How To Use]]
([TIME[2015-09-04 03:05:03 +09:00]] 版)
<http://curl.haxx.se/docs/manpage.html>
]FIGCAPTION]

> Since 7.21.7, this option is superfluous since you can specify a socks5 hostname proxy with -x, --proxy using a socks5h:// protocol prefix.

]FIG]


[FIG(quote)[
[FIGCAPTION[
[56] [CITE[cURL - How To Use]]
([TIME[2015-09-04 03:05:03 +09:00]] 版)
<http://curl.haxx.se/docs/manpage.html>
]FIGCAPTION]

> As part of the GSS-API negotiation a protection mode is negotiated. RFC 1961 says in section 4.3/4.4 it should be protected, but the NEC reference implementation does not. The option --socks5-gssapi-nec allows the unprotected exchange of the protection mode negotiation. (Added in 7.19.4).

]FIG]

[58] [CITE@en[280661 – SOCKS proxy server connection timeout hard-coded]]
([TIME[2015-09-14 23:34:24 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=280661>

[59] [CITE@en[16103 – SOCKS V5 Implementation]]
([TIME[2015-09-14 23:38:28 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=16103>

[60] [CITE@en[133939 – ''''''[''''''RFE'''''']'''''' SOCKS: cannot use kerberos v5 (GSS-API) authentication with]]
([TIME[2015-09-14 23:40:17 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=133939>

[61] [CITE@en[78176 – PAC: SOCKS return value is not version specific]]
([TIME[2015-09-14 23:43:16 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=78176>

[62] [CITE[Configuring a SOCKS proxy server in Chrome - The Chromium Projects]]
([TIME[2015-09-14 19:33:20 +09:00]] 版)
<https://www.chromium.org/developers/design-documents/network-stack/socks-proxy>

[63] [CITE[Issue 29914 - chromium - DNS queries not forwarded through SOCKS v5 proxies - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-09-14 23:51:54 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=29914>

[64] [CITE[Issue 469 - chromium - Support SOCKS proxy - An open-source project to help move the web forward. - Google Project Hosting]]
([TIME[2015-09-14 23:58:17 +09:00]] 版)
<https://code.google.com/p/chromium/issues/detail?id=469>

[FIG(quote)[
[FIGCAPTION[
[65] [CITE@en[''''''[''''''chrome'''''']'''''' Contents of /trunk/src/net/socket/socks_client_socket.cc]]
([TIME[2015-09-15 00:02:58 +09:00]] 版)
<http://src.chromium.org/viewvc/chrome/trunk/src/net/socket/socks_client_socket.cc>
]FIGCAPTION]

> 
> 303	    // Resolving the hostname failed; fail the request rather than automatically
> 304	    // falling back to SOCKS4a (since it can be confusing to see invalid IP
> 305	    // addresses being sent to the SOCKS4 server when it doesn't support 4A.)

]FIG]


[FIG(quote)[
[FIGCAPTION[
[66] [CITE[net/socket/socks_client_socket.cc - Issue 113811: Adding socks4 support for chromium. tested for windows and linux.... - Code Review]]
([TIME[2015-09-15 00:10:29 +09:00]] 版)
<https://codereview.chromium.org/113811/diff/11012/net/socket/socks_client_socket.cc>
]FIGCAPTION]

> 
>  210   if (ok) {
>  211     DCHECK(addresses_.head());
>  212 
>  213     // If the host is resolved to an IPv6 address, we revert to SOCKS4a
>  214     // since IPv6 is unsupported by SOCKS4/4a protocol.
>  215     struct sockaddr *host_info = addresses_.head()->ai_addr;
>  216     if (host_info->sa_family == AF_INET) {
>  217       DLOG(INFO) << "Resolved host. Using SOCKS4 to communicate";
>  218       socks_version_ = kSOCKS4;
>  219     } else {
>  220       DLOG(INFO) << "Resolved host but to IPv6. Using SOCKS4a to communicate";
>  221       socks_version_ = kSOCKS4a;
>  222     }
>  223   } else {
>  224     DLOG(INFO) << "Could not resolve host. Using SOCKS4a to communicate";
>  225     socks_version_ = kSOCKS4a;
>  226   }

]FIG]

[57] [CITE@en[122752 – SOCKS: Username/Password Authentication (V5)]]
([TIME[2015-09-14 23:33:41 +09:00]] 版)
<https://bugzilla.mozilla.org/show_bug.cgi?id=122752>

[82] [CITE[Dante - Documentation]]
([TIME[2015-08-27 23:18:16 +09:00]] 版)
<https://www.inet.no/dante/doc/>

[FIG(quote)[
[FIGCAPTION[
[83] ([TIME[2015-09-17 23:56:16 +09:00]] 版)
<http://www.novell.com/documentation/nbm39/administration/data/b7qgmq8.html>
]FIGCAPTION]

> None: No authentication. However, data is encrypted if the Secure Sockets Layer (SSL) option is also selected.
> Clear Text User/Password: During Novell IP Gateway user authentication, the user’s password is transmitted across the wire in clear text without encryption. The password is checked against the password stored in NDS, but this is not the same as NDS authentication. However, if SSL is also selected, the password is encrypted before being sent.
> NDS User/Password: The user is authenticated using the NDS username and password with a scheme that protects the secrecy of the password. However, data is not encrypted unless the SSL option is also selected. This option works only if the SOCKS 5 client software supports NDS authentication.
> SSL: The SSL option requires that an SSL connection between the client and the server be established before the Novell IP Gateway can authenticate a user by using any of the other authentication schemes. Enabling this option also ensures the encryption of all data transmitted between the client and the server.
> Key ID: If you select the SSL authentication scheme, you must also select a Key ID from the drop-down list. At least one Key ID must be created for the server in NDS prior to the selection of SSL. Novell Public Key Infrastructure (PKI) Services must be installed on your server.

]FIG]

[183] [CITE@en[284371 – SOCKS4A support]]
([TIME[2016-09-01 15:49:46 +09:00]])
<https://bugzilla.mozilla.org/show_bug.cgi?id=284371>

[184] [CITE@en[134105 – SOCKS5: DNS lookups (host resolving) should occur on proxy, not client side.]]
([TIME[2016-09-01 15:51:12 +09:00]])
<https://bugzilla.mozilla.org/show_bug.cgi?id=134105>

[187] [CITE@en[Limit valid range for socksVersion]]
([[shs96c]]著, [TIME[2017-05-04 17:07:43 +09:00]])
<https://github.com/w3c/webdriver/commit/afb549ef09f36053f027cc53b2528f14c3aee908>

[188] [CITE@en[Socks Proxy requires Socks Version]]
([[shs96c]]著, [TIME[2017-08-16 22:14:34 +09:00]])
<https://github.com/w3c/webdriver/commit/01d01ab530d7070372af9ec4fd486c0f5b478543>

[189] [CITE@en-US[SOCKS Proxies in Internet Explorer – IEInternals]]
([TIME[2017-08-26 12:10:28 +09:00]])
<https://blogs.msdn.microsoft.com/ieinternals/2010/10/08/socks-proxies-in-internet-explorer/>