今回はプロトコルについて話してみます。
インフラエンジニアをやっていると、「 プロトコルを知っているかどうか」というのが他のエンジニアと差がつく部分のひとつになります。
そこで知っておきたいのが、まずtelnetについてです。
「手動でプロトコルを送る道具」としてのtelnet
ssh以前はコンピュータに接続するにはtelnetが多かったわけですが(rloginとかrshとかもありましたけど) 、telnet自体はtelnetサーバ(telnetdなど)とやりとりしてコンピュータと接続する(ログインする)ためのコマンドであると同時に、平文を無手順で送受信できるため、平文のプロトコルであれば手入力で再現することができる道具でもあります。
telnetのsyntaxは
$ telnet [option] [host [port]]
です。hostがないとportが書けないので[host] [port]ではないのと、host自体も省略できます(その場合interactiveモードに入ります。helpと打つとコマンド一覧が出ます) 。
portを省略すると23/tcp(telnetのwell known port)に接続されますが、ここでSMTPやHTTPなどのwell known port(25や80)を指定して起動すると、それらのサーバと接続することができます。
バイナリプロトコルには使えません
残念ながら平文以外(バイナリプロトコルや暗号化するプロトコル)や、UDP上のプロトコルはtelnetでは扱えませんが、暗号化やUDPとのやり取りは、そういうツールを作れば平文でやりとりすることができるようになります。
バイナリプロトコルは専用のツールを作るしかありません。とはいえ、バイナリプロトコルのためのツールを作るのはさほど難しいことではないので、チャレンジしてみるのもいいと思います。たとえばPerlだとバイナリプロトコルを扱えるCPANモジュールがたくさんあったりしますし、なくてもプロトコルフォーマットさえわかれば作れます。筆者は昔、PerlでNTPを扱えるモジュールがないので、そういうスクリプトを書いたことがあります。Perlの場合は、pack、unpackとビットシフト、あとはsocket操作ができれば自由自在です。
UDPの扱いや暗号化するプロトコル、バイナリプロトコルについてはまた機会があれば紹介するとして、今回はTCP上の平文プロトコルに限定して解説してみます。
まずはプロトコルを知るところからです。
プロトコルの原典「RFC」
プロトコルはRFCに書いてあります。RFCについても近々この連載でとりあげたいと思いますが、RFCは誤解を怖れずに超簡単に言えば「インターネット上の各種の約束について書いてある文書」です。
RFCにはInformationalやDraft、Standardなど各種の「状態」があります。本来であればStandardが「標準の」状態になるわけですが、RFCは法律ではなく「提案された約束事」なので、常にStandardを参考にして実装されているわけではなく、Draft状態で実装されているケースもありますから、そこは適宜使い分けましょう。
RFCの公式な置き場所は以下になります。
Request for Comments (RFC)
URL:http://www.ietf.org/rfc.html
ただ、RFCは各所にコピー(ミラー)されていますので、手に入れやすいところを探しましょう。ミラーポリシー的に許されるのであれば、組織ごとにコピーを置いても良いと思います(いまのミラーポリシーは把握していませんすみません) 。
また、RFCは全部英語ですが、有志の方々による日本語化されたRFCもたくさんあります。最新のRFCは訳されていないことも多いので、そういう時は英語を頑張って読みましょう。
RFCの読み方
RFCで最初にぶつかる壁は「どれを読めばいいかわからない」という点です。もちろん検索することもできますが、執筆時点で6000を越えているので、適切なRFCに辿りつけない可能性もあります。
たとえばDNSのRFCといえばまずはRFC1034ですが(筆者的には) 、このRFC1034は、“ Domain names - concepts and facilities” というタイトルなので、“ DNS” で検索しても引っかかりません。このあたりは正直「慣れ」るしかない部分もあります。
以下のURLに全RFCの一覧があるので、このファイルを検索したりざっと眺めてみるのも良いと思います(RFCトップページ で検索フォームを使うより速いです) 。
RFC INDEX
URL:http://www.ietf.org/rfc/rfc-index.txt
この一覧(そして個々のRFCの文頭にもありますが)には「Status」という部分がありますが、ここがそのRFCの状態を表しています。
もうひとつ見るべきところが、「 Obsoletes」もしくは「Obsoleted by」という部分です。このどちらも書いてないRFCもたくさんありますが、「 Obsoletes」と書いてあるのは、他のRFCを「時代遅れにしている」という意味─つまり更新版であるということです。「 Obsoleted by」はその逆で、他のRFCによって「時代遅れにされている」という意味になります。つまり「Obsoleted by」のRFCは基本読む必要がありません(昔のRFC実装をしているサーバの挙動を調べるときなどは読む必要があるかもしれません) 。
またこれとは別に「Updates」と「Updated by」という記述がある場合もあります。「 Obsoletes」「 Obsoleted by」は文書まるまるについて更新している、されているという場合ですが、「 Updates」「 Updated by」は文書の一部分について更新している、されているというケースになります。「 Updated by」が付いていても、その文書は有効な部分がある(ことがある)ということになります。
平文プロトコルを「手でしゃべる」
筆者はプロトコルを暗記しているのはSMTP、HTTP、POP3くらいです。平文でまず暗記すべきなのはこのあたりではないでしょうか(最近ならPOP3はいらないかもしれません) 。
たとえばSMTPを「手でしゃべる」のは下記のようになります(qmail-smtpdに接続した例です) 。
$ telnet 0 25
Trying 0.0.0.0...
Connected to 0 (0.0.0.0).
Escape character is '^]'.
220 hostname.domainname ESMTP
ehlo localhost
250-hostname.domainname
250-PIPELINING
250 8BITMIME
mail from: [email protected]
250 ok
rcpt to: [email protected]
250 ok
data
354 go ahead
from:
to:
subject: test
test
.
250 ok 1301293631 qp 31290
quit
221 hostname.domainname
Connection closed by foreign host.
$
このうち、SMTPに該当するのは下記の部分になります。
ehlo
mail from:
rcpt to:
data
.
quit
まずグリーティングメッセージがサーバから送られています。ESMTPというは拡張SMTPをサポートしていますよ、という意味です。
ehloはこちらの(クライアント側の)ホスト名を伝えるコマンドです。
mail from: とrcpt to: はメールエンベロープの送信元と送信先を指定するコマンドです。dataは実際のメールのヘッダとボディを送信するコマンドです。ヘッダに続く最初の空行以降がボディという約束になっています。
また単独の.がdataの終わりを意味しています。最後にquitでプロトコルを終了して、この時点でメールが送信されます。
これを見ると、メールのエンベロープとヘッダは別物ということがよくわかります。メールのヘッダはプロトコル的にはただのテキストです。サーバの実装によってはehloは略しても大丈夫なケースが多いので、筆者はよく省略していました(本当はいけませんが) 。
上記の例のように、手動でプロトコルをしゃべるのは何ら難しいことではないのがわかると思います(平文であれば、ですが) 。
注意点として、シェルプロンプトから telnet 0 25 としていますが、この0というのはINADDR ANYを意味しているのですが、この表記をサポートしていないケースもあるので、その時は明示的にlocalhostやSMTPサーバのアドレス(ホスト名)を指定しましょう。
ちなみにSMTPの執筆時点でのRFCは5321になります。元々はRFC821という非常に有名なRFC番号(インフラエンジニアであれば、まず最初に覚えるといっても過言ではない)だったのですが、これが2821にObsoleted byされて、さらに5321にObsoleted byされて今日に至ります。余談ですが、SMTPは非常にメジャーなプロトコルのため、821を2821、そして5321でObsoleteと、番号で韻を踏んでいるのがわかります。
次回はこの続きでHTTPプロトコルについて解説してみたいと思います。