SOCKS4プロトコル

2001.12.13
PCB


!注意!
このコンテンツはPCBの勝手な解釈に基づいており、内容が正しいことを保証することはできません。
正しい情報を得たいのなら、NEC USAのサイトで公式の資料を入手されることをお勧めします。
ただ、間違いなどがあればメールなどで指摘していただければうれしいです。
また、このコンテンツの公開に問題があれば、メールなどで連絡をください。早急に対処いたします。
ぼくが自分なりに読んだ限りでは、NEC USAのサイトには配布制限などは見当たりませんでした。
この文書について
この文書では、SOCKS4プロトコルに関する簡単な解説をしています。
何故こんなものを書いたかというと、ぼくが探した限りではSOCKS4の日本語での解説はインターネット上には
見つけることができなかったからです。
現在、ぼくはIE5.5を主に使っていますが、プロキシとしてはSOCKS4プロトコルにしか対応していません。
何故広く使われているプロトコルなのに、日本語訳がないとは・・・と思い、自分で書いてみようと思い立ったわけです。

また、この説明を読む前提として、

・ネットワークについてのある程度の基礎的な知識を持っている。
・「プロトコル」というものがナニモノか分かっている。
・HTTPプロキシがどういうものか大体知っている。
・英語があまり得意ではない。

というような人が対象となっています。
ある程度基礎的な事は説明していませんので、分からなければ検索サイトなどで探してみてください。
あと、英語が読める方はぜひぜひNEC USAのサイトで公式の資料を見てください。こんな変な説明より
遥かに分かりやすいと思います。

SOCKSとは。
SOCKSとは、NEC USAが考案した一種のプロキシ・プロトコルです。主にファイアウォールなどを
超えての通信を実現するためにつくられました。
従来のHTTPプロキシとは違い、HTTP,FTP,SMTPなど一般的なプロトコルのほとんどから
利用することができます。
ただし、その際にはクライアント側でSOCKSに対応させておく必要があります。
現在、SOCKSには2つのバージョンSOCKS4,SOCKS5があり、そのうちSOCKS5の方は
既にRFC化されています。(RFC1928)
このうち、この文書ではSOCKS4についての説明をしたいと思います。

SOCKS4の概要
SOCKS4プロキシの接続形態は、基本的にはHTTPプロキシと変わりません。クライアントサーバーの間に
介入して、通信を受け渡します。
C/Sモデル?まぁこんなカンジ。
ただし、SOCKS4にはいくつかの制限があります。
これらの問題は、SOCKS5においては解決されています。

プロトコルの概要 - リクエストパケット
まず、クライアントSOCKSサーバーの接続が確立されると、クライアント側から接続に関するリクエスト
パケットが送信されます。
リクエストパケットの内容は下の通りです。


RFCを読んでいるとよく出てくる図なのですが、見たことがない方には少し分かりづらいかもしれません。
データは左から順に送られていって、四角く区切られたフィールドにはそれぞれ名前がついています。
また、それぞれのフィールドの下の数字は各フィールドのサイズ(バイト単位)を示しています。
それぞれのフィールドの内容は次の通りです。
VN
Version Numberの略。SOCKSのバージョンの値です。
SOCKS4なので、「4」でなければなりません。
CD
CommanDの略。SOCKSの動作を示す値です。
後述するとおり、この値によってCONNECT,BINDという二つのコマンドに分かれることになります。
CONNECTなら1、BINDなら2が指定されます。
DSTPORT
DeSTination PORT numberの略で、ポート番号の値です。CONNECT,BINDによって意味は異なります。
ネットワークバイトオーダーで格納されているので注意が必要です。
DSTIP
DeSTination IP addressの略で、アドレスの値です。これもモードによって意味が異なり、
ネットワークバイトオーダーで格納されています。
たとえば192.168.1.2というアドレスなら、「C0 A8 01 02」という順番になっています。
USERID
ユーザーIDを示す文字列です。長さは決まっていません。
かわりに文字列の終わりをNULLで判定します。NULLとは、簡単にいうと「0」のことです。
どうでしょう、分かったでしょうか?

ちなみに、下線の引いてあった「ネットワークバイトオーダー」ですが、これについて知らない方の為に説明します。
この上なく分かりづらい説明だとは思いますが、ぼくの能力ではこれが精一杯です。知っている方は
読み飛ばして結構です。

ネットワークバイトオーダー

Windowsでは、普通数値を表現するのに4バイト、32bitを使用します。そして、この数値をメモリに配置するとき、
視覚的には逆にして格納するのが普通です。
たとえば、「8462」という数値があったとします。これは、16進数に直すと210Ehとなります。(hは16進数だという意味)
そして、これをメモリに格納するときには、「0E 21 00 00」という風になります。逆になって格納されていますね。
これをリトルエンディアンと呼びます。
ところが、ネットワーク通信に使われる数値の表現形式はネットワークバイトオーダー、別名ビッグエンディアンなのです。
すると、さっきの例でいうなら、210Ehはそのまま「00 00 21 0E」となって格納されます。
なので、この値を使用するときはバイトオーダーの変換をしなければなりません。
これを忘れるととんでもない数値になってしまうことがしばしばあります。注意しましょう。(ぼくの経験上)

プロトコルの概要 - CONNECTモードとBINDモード
クライアントからリクエストパケットが送信されました。SOCKSサーバーはまずそのリクエストを解釈します。
ここで重要となるのが、リクエストパケット中の「CD」フィールドです。上の説明にもあったとおり、これにはコマンドを示す値が
入っています。SOCKSサーバーはこの値によって動作を決定します。
こうして動作の種類を変えるのは、TCPにおける接続の種別が二つあることに起因しています。簡単に言ってしまえば、
接続する方か、接続される方か、です。ただし、HTTPやSMTPなど有名なプロトコルのほとんどは、クライアント
接続し、サーバークライアントからの接続を待つようになっていますので、SOCKSのリクエストはたぶんCONNECTの
方が多いでしょう。

しかし、なかにはそうでないプロトコルもあります。その代表的な例がFTP(File Transfer Protocol)です。よく
ホームページのデータをアップロードするのに使われる有名なプロトコルです。しかし、実はこのプロトコルでは
クライアントサーバーからの接続を待つことになる場合があります。それは、ファイルをアップロード・ダウンロードする時
です。

というのも、FTPではファイルの内容を送受信するときにはそのファイル専用の接続をもう一つ開くからです。そしてその時
普通の設定なら、クライアントが接続を待ち、サーバークライアントに接続するという形態をとります。なので、
そういうときにはBINDモードでSOCKSサーバーに接続を待ってもらって、FTPサーバーSOCKSサーバーへ接続して
もらうことになります。

プロトコルの概要 - CONNECTモードの場合
CONNECTモードのリクエストが入った場合のSOCKSサーバーの動作を考えてみましょう。

リクエストの解釈が終わった時点でまずSOCKSサーバーが行うのは、USERIDの照合です。もし、USERIDが
不正であるなどの理由でクライアントの要求を拒否する場合には、接続を行わずに返答の送信に移ります。

そこで認証に成功すれば、SOCKSサーバーはDSTIP,DSTPORTがそれぞれ指すIPアドレスのポートへ接続を試みます。
接続に成功するか、もしくは失敗した時点でクライアントに返答を送信します。


さっきのリクエストパケットと似ていますが、USERID以下がありませんね。各フィールドの解説をします。
VN
返答パケットのバージョン番号の値です。
注意しなければならないのは、これはSOCKSのバージョン番号ではないということです。
SOCKS4なら、0が格納されます。
CD
これはリクエストパケットと同じ名前ではありますが、意味はまったく異なります。
このフィールドには接続の可否を示す値が格納されます。値は次の通りです。

90・・・認証に成功し、接続が確立された(request granted)
91・・・なんらかの理由で失敗した(request rejected or failed)
92・・・認証には成功したが、接続に失敗した
93・・・認証に失敗した
DSTPORT,DSTIP
一応フィールドとして存在はしていますが、意味は全くありません。大抵の場合は0が格納されていると
思いますが、保証は無いのでこのフィールドは無視してください。
VNとCDの内容に注意してください。特にVNに至っては、ぼくもこの文書を書くまで知らなかった。・・・というのは秘密です。

この返答パケットを送信した後、CDフィールドが90(request granted)ならRelayモードに入ります。失敗なら
SOCKSサーバーはすぐにクライアントとの接続を切断します。

プロトコルの概要 - BINDモードの場合
さて、こんどはBINDモードについて説明していきましょう。

BINDモードでもやはり、最初にUSERIDの照合が行われます。ここで注意しなければならないのが、BINDモードが
使用できるのは先にクライアントがCONNECTモードで接続しているサーバーとの通信のみ
、ということです。
DSTPORT,DSTIPには先に接続しているCONNECTモードの接続のDSTPORT,DSTIPを入れておきます。また、
USERIDにも先の接続と同じものを指定します。これらが違うものであってはいけません。

これらの認証を終えた後、もし成功したならSOCKSサーバーはポートを一つ確保します。そして1つ目の返答パケットを
送信します。この返答パケットの構成は、CONNECTモードのパケットとほとんど同じです。

VN
返答パケットのバージョン番号の値です。
CONNECTモードの返答パケットと同じく、このバージョン番号はSOCKSのバージョン番号ではありません。
SOCKS4なら、0が格納されます。
CD
認証が成功したかどうかを示す値が格納されます。

90・・・認証に成功し、ソケットが確保された(request granted)
91・・・なんらかの理由で失敗した(request rejected or failed)
92・・・認証には成功したが、ソケットの確保に失敗した
93・・・認証に失敗した
DSTPORT
CDフィールドが90で、ソケットの確保に成功していればSOCKSサーバーに確保されたソケットのポート番号が
格納されます。
DSTIP
CDフィールドが90で、ソケットの確保に成功していればSOCKSサーバーのIPアドレスが格納されます。
これは必ずしもクライアント側から見たSOCKSサーバーのIPアドレスと一致するとは限りません。
また、成功したのに値が0、IPアドレスに直すと0.0.0.0が格納されている場合は、SOCKSサーバーのIPアドレスを
そのまま接続に使用してかまいません。
CONNECTモードと同じく、この返答パケットを送信した後CDフィールドが90(request granted)でなければ、SOCKS
サーバー
はすぐにクライアントとの接続を切断します。
成功していれば、SOCKSサーバーサーバーからの接続を待つことになります。この後、クライアントは最初に確立した
CONNECTモードの接続を使って、サーバーSOCKSサーバーのIPアドレスとポート番号を通知します。


サーバーSOCKSサーバーに接続してきたら、まずリクエストパケットと接続してきたサーバーのIPとの照合が
行われます。もし二つのIPアドレスが異なれば、接続は確立されません。
照合を行った後、SOCKSサーバークライアントに2つ目の返答パケットを送信します。


このパケットの各フィールドの内容は次の通りです。
VN
これも1つ目の返答パケットと同じく、バージョン番号です。0が格納されます。
CD
接続が成功したかどうかを示す値です。

90・・・IPアドレスが照合され、接続が確立された
91・・・IPアドレスの照合に失敗した(リクエストパケットのDSTIPフィールドと実際に接続してきたホストのIPが違う)
DSTPORT,DSTIP
無視されます。
今回はCDフィールドは90か91のどちらかしかありません。
また、1つ目の返答パケットと同じように、CDフィールドが90(request granted)以外なら、クライアントの接続は
すぐに切断されます。
成功なら、めでたくRelayモードへと移行します。

プロトコル概要 - Relayモード(仮)
CONNECTモード、BINDモードのどちらでも、接続が完了するとRelayモードへと移行します。
ここで注意ですが、Relayモードというのはぼくが勝手につけた名前であり、公式の仕様書には全く載っていません。
説明を簡略化するための言葉ですので、あんまり公には言わないほうがいいかもしれません。

Relayモードとは、クライアント - SOCKSサーバー - サーバーという三者間の接続が完全に確立され、あとは
SOCKSサーバーが二つのマシンの間のデータを受け渡ししている、という状態のことです。
このモードに入ると、クライアントから見てもサーバーから見ても、あたかも直接相手と通信をしているかのようになります。

終わりに
これでSOCKS4のプロトコルの説明はすべて終了です。どうだったでしょうか。
ぼくはこんなテキストを書くのは初めてなので、なるべく分かりやすいように努力はしたつもりですが、なかなか
読みづらいかもしれません。

しかし、SOCKS4プロトコル自体は実に簡単で、かつ画期的なプロトコルです。なぜなら、Relayモードに入ってしまえば
あとは普通の通信と全く変わらなくなってしまうので、既存のプログラムをSOCKSに対応させる手間がそれほど
かからないからです。ファイアウォールを越える目的にはとても有効です。

確かにこのSOCKS4にも、最初に書いた通りいくつか弱点があります。しかし、RFC化されていないプロトコルにも
かかわらず、現在多くのソフトウェアがこのプロトコルに対応しているのは、簡単さと便利さを兼ね備えているからだと
思います。

とりあえず、この文書を読んで「SOCKSってこういうものなんだ」と思っていただければうれしいです。
PCB

参考文献
SOCKS: A protocol for TCP proxy across firewalls
Ying-Da Lee
Principal Member Technical Staff NEC Systems Laboratory, CSTC

http://www.socks.nec.com/protocol/socks4.protocol