NET // communication networks
LESSON 16 / 標準編

telnet で覗くアプリ層プロトコル ─ HTTP / SMTP / POP3 / FTP

これまでの第12〜15回で HTTP・DNS・メール・FTP を仕様の側から学びました。本講ではそれらを telnet で実際に開いて、サーバとのコマンド対話を生で見る 観察回です。古典的なアプリ層プロトコルは 「TCP の上にテキストコマンドを並べただけ」。telnet で 80 / 25 / 110 / 21 番ポートに接続すれば、ブラウザやメーラが普段やっている会話を 1文字ずつ手打ち で再現できます。手で打ってこそ「プロトコルの正体」が腹落ちする、標準編のクライマックス的なハンズオン回です。

学習目標

本講を終えると、以下を達成できるようになります。

本講は 第12回 HTTP/1.1・HTTP/2 詳細第14回 メール詳細第15回 FTP の上に乗る観察回です。各プロトコルの「仕様(コマンド・ステータスコード・状態遷移)」はそれぞれの回ですでに学んだ前提で、ここでは 同じ仕様を手で動かして体感する ことに集中します。本講で扱うのは 平文版 のみ。各プロトコルを TLS で覆ったセキュア化版(HTTPS・SMTPS・IMAPS・POP3S・FTPS・SFTP)は 第36回 アプリ層プロトコルのセキュア化 でまとめて扱います。さらに踏み込んで「自分で HTTP クライアントを書く」ところまで行きたい人は、発展編 HTTP プログラミング へ。

このレッスンの目次

01 なぜ telnet で覗くか HTTP・SMTP・POP3・FTP には共通の作りがあります。 すべて TCP 上… 02 環境準備 本講のすべての節は、手元の telnet クライアント 1つで実演できます。サーバ側… 03 HTTP を覗く まずは一番馴染みのある HTTP から。 第12回 で学んだ HTTP/1.1 のメ… 04 SMTP を覗く HTTP が「1リクエスト → 1レスポンス」なのに対し、SMTP は 多段階のセッ… 05 POP3 を覗く POP3(Post Office Protocol v3) は 「メールサーバから受… 06 FTP を覗く FTP の独特な点は、 制御コネクション(21) と データコネクション(20 か動… 07 4 プロトコル比較 ここまでで見てきた4プロトコルを横並びにすると、共通点と固有の癖がはっきりします。 08 何が見えなくなるか telnet で覗けるのは 「平文 TCP 上のテキストプロトコル」 だけ。現代のプ… 09 まとめ 本講の重要語句を整理 10 確認問題 理解度を問題でチェック

なぜ telnet で覗くのか ─ 古典プロトコルの共通原理

HTTP・SMTP・POP3・FTP には共通の作りがあります。すべて TCP 上のテキストプロトコル で、「クライアントが行を1つ送る → サーバが行で答える」 の繰り返しでセッションが進みます。だから TCP に文字列を流せるだけのツール(=telnet) があれば、人間がクライアントの代わりを務められます。
POINT 古典アプリ層プロトコルの3つの共通点:
テキストベース(全部 ASCII 文字列。バイナリではない)
行末は CRLF(\r\n)(SMTP・POP3・FTP の RFC が明示。HTTP/1.1 も同じ)
3桁の数値ステータスコード(HTTP は 200/404/…、SMTP は 220/250/550、FTP は 220/331/230 など。POP3 だけは +OK / -ERR)

「TCP の上に何が乗っているか」を一目で

同じ TCP の上に、似た作りの会話が乗っている HTTP / port 80 → GET / HTTP/1.1 → Host: example.com → (空行) ← HTTP/1.1 200 OK ← (ヘッダ・本文) 1 リクエスト 1 レスポンス SMTP / port 25 ← 220 ready → EHLO me → MAIL FROM:<a> → RCPT TO:<b> → DATA → ... → . → QUIT セッション = 多段階対話 POP3 / port 110 ← +OK ready → USER alice → PASS secret → LIST → RETR 1 → QUIT +OK / -ERR 形式 FTP / port 21 ← 220 welcome → USER alice → PASS secret → PWD / SYST → TYPE I / PASV → QUIT 制御接続のみ telnet で見える

図の見方:4プロトコルとも基本構造は同じ ── クライアント → サーバ の行(矢印 →)と サーバ → クライアント の行(矢印 ←)が交互に流れる。違いは「コマンド名」と「ステータス記法」だけ。だから telnet 1つあれば全部覗ける。

つながる知識: なぜ古典プロトコルは テキスト なのか? 1970〜80年代にこれらが設計された頃、マシンごとにバイナリ表現が違う(エンディアン・文字コード・整数長) ことが大問題でした。「人間が読めて、どのマシンでも解釈にブレが出ない ASCII 文字列」が安全策だったのです。現代の HTTP/2・gRPC・QUIC はバイナリですが、それは パフォーマンス重視 + ライブラリで完全に隠蔽できる 時代になったから。テキスト派とバイナリ派の歴史については 第11回 階層化 も参照。

環境準備 ─ telnet とテストサーバ

本講のすべての節は、手元の telnet クライアント 1つで実演できます。サーバ側は「公開のテストサーバを使う」「自分でローカルに立てる」のどちらかです。

① telnet クライアント

Windows / macOS とも標準コマンドから外れている / 無効化されているので、必要なら以下で代替してください:

導入のヒント:
Windows:Telnet クライアントを「Windows の機能の有効化」 で有効化、または PuTTY の Raw モード
macOS:brew install telnet でインストール、または nc -C example.com 80 で代用
共通:openssl s_client -crlf -connect example.com:443 なら HTTPS にも使える(本講でも後半で使用)

② テストサーバ

各節で叩く相手として、以下のいずれかを用意してください。詳しい手順は各節で示します。

推奨サーバ 代替
03 HTTPexample.com:80(IANA 公式)自分のサイト、python -m http.server 8000
04 SMTPローカル MailHog(docker run mailhog/mailhog で 1025 番)Mailcatcher、Postfix のローカル起動
05 POP3ローカル Dovecot または GreenMail 等のテストサーバ所属組織で許可された自前メールサーバ
06 FTPtest.rebex.net:21(読取専用テストサーバ・demo/password)ローカル vsftpd、docker run -p 21:21 ...
注意: 他人のメールサーバ・FTP サーバに無許可で telnet することは絶対にやめてください。多くのサーバはアクセス試行をログに残し、不正アクセスとして扱う場合があります。学習用には 自分の PC 内 か、「テスト目的で公開されている」と明示されたサーバ(test.rebex.net など) のみを使うのが鉄則です。
もっと詳しく:Docker で MailHog を起動する例
# SMTP=1025、Web UI=8025
$ docker run -d --rm -p 1025:1025 -p 8025:8025 mailhog/mailhog

# 確認
$ telnet localhost 1025
220 mailhog.example ESMTP MailHog

MailHog は「届いたメールを実送信せずに溜めて Web UI で見せる」開発用 SMTP。テスト学習に最適。

HTTP を覗く ─ ポート 80 / 1 リクエスト 1 レスポンス

まずは一番馴染みのある HTTP から。第12回 で学んだ HTTP/1.1 のメッセージ構造(リクエスト行 + ヘッダ + 空行 + 本文) を、telnet で実際に組み立ててみます。
POINT HTTP を手で打つときの3つの掟:
① 行末は必ず CRLF(\r\n)。LF(\n) だけだと多くのサーバが受け付けない
② ヘッダの最後に 空行(CRLF だけの行) を必ず入れる ── これが「ヘッダ終わり」の合図
③ HTTP/1.1 は Host ヘッダが必須。書かないと 400 Bad Request になる

walkthrough:example.com に GET を打つ6ステップ

STEP 1 ── サーバに TCP 接続する

$ telnet example.com 80
Trying 23.215.0.136...
Connected to example.com.
Escape character is '^]'.

telnet は 引数で指定したホスト・ポート に TCP 接続するだけのツール。ここまでで TCP の 3-way ハンドシェイクが完了しています(下層は 第18回 TCP)。

STEP 2 ── リクエスト行を打つ

GET / HTTP/1.1

「メソッド SP URI SP HTTP-バージョン」。Enter キーで CRLF を送ります。

STEP 3 ── Host ヘッダを打つ

Host: example.com

HTTP/1.1 で必須の Host ヘッダ。同じ IP に複数のサイトが同居している前提なので、これを書かないと「どのサイトの / を要求しているか」サーバに伝わりません(バーチャルホスト)。

STEP 4 ── 空行を打つ(超重要)

(ここで Enter だけ = CRLF だけの行)

「ヘッダ終わり、本文に入ります」の合図。GET には本文がないので、空行直後にサーバが処理を開始します。

STEP 5 ── レスポンスを受け取る

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
Date: Sun, 26 Apr 2026 03:21:08 GMT

<!doctype html>
<html>
<head>…</head>
…

サーバから ステータス行 → ヘッダ → 空行 → 本文 が流れてきます。Content-Length の数だけ本文を読めばよい、というのがクライアントの基本動作。

STEP 6 ── コネクションを切る

Connection closed by foreign host.

HTTP/1.1 はパーシステント接続がデフォルトですが、サーバのアイドルタイムアウトを過ぎるとサーバ側から切ってきます。telnet は ^](Ctrl+]) → quit でも切れます。

観察ポイント

Q. GET / HTTP/1.0GET / HTTP/1.1 で、応答に何が変わるでしょう?

実環境では多くのサイトが HTTPS のみ(80 番は 301 で 443 にリダイレクト) です。telnet は平文しか喋れないので、TLS 越しの HTTPS には接続できません。HTTPS で生 HTTP を打ちたい場合の手段は、TLS そのものを学んだ 第36回 アプリ層プロトコルのセキュア化 で扱います。

SMTP を覗く ─ ポート 25 / セッション型の対話

HTTP が「1リクエスト → 1レスポンス」なのに対し、SMTP は 多段階のセッション。サーバが 220 で挨拶 → クライアントが EHLO で名乗り → 送信元・宛先・本文を順に渡す ── という流れを テキストの行 で進めます。第14回 メール詳細 で学んだコマンドを実際に手で打ってみましょう。
POINT SMTP の対話は 必ず順序がある:
EHLO → MAIL FROM → RCPT TO(複数可) → DATA → 本文 → 単独の「.」 → QUIT
サーバ応答は 3桁コード(2xx 成功 / 3xx 中継 / 4xx 一時失敗 / 5xx 永続失敗)。本文終了の合図は 「.」だけの行(CRLF).CRLF が頻出する地雷。

walkthrough:ローカル MailHog に1通送る

Docker で MailHog を起動してある前提で、localhost:1025 に接続します(本番 SMTP なら 25 / 587)。

$ telnet localhost 1025
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mailhog.example ESMTP MailHog      ← サーバが先に挨拶

EHLO mybox.local
250-Hello mybox.local
250-PIPELINING
250 AUTH PLAIN

MAIL FROM:<from@example.com>
250 Sender from@example.com ok

RCPT TO:<to@example.com>
250 Recipient to@example.com ok

DATA
354 End data with <CR><LF>.<CR><LF>

Subject: Hello via telnet
From: from@example.com
To: to@example.com

This is the body.
.
250 Ok: queued as ABC123

QUIT
221 Bye
Connection closed by foreign host.

観察ポイント

本番 SMTP では: 公開のメールサーバ(smtp.gmail.com など)に対して、上のような平文 SMTP の対話は ほぼ確実に拒否 されます。理由は (1) ポート 25 への直接接続は ISP がブロックしていることが多い / (2) 587 番(submission)は 暗号化と認証 が要求される / (3) 第三者宛て(自ドメインでない RCPT TO) は open relay 防止 のため拒否、というガードが幾重にも掛かっているため。学習目的の SMTP 観察は必ずローカル MailHog 等で行ってください。本番のサーバに対して TLS 経由で同じ対話を覗く方法は 第36回 で扱います。

POP3 を覗く ─ ポート 110 / +OK / -ERR の世界

POP3(Post Office Protocol v3) は 「メールサーバから受信箱を持ち帰る」 ための古典プロトコル。SMTP と違って 3 桁コードではなく +OK(成功)/ -ERR(失敗)という独特な記法を使います。RFC 1939 で定義された、よりシンプルな世界です。
POINT POP3 セッションの基本:
USER(ユーザ名)→ PASS(パスワード)→ STAT(件数とサイズ)→ LIST(各メールのサイズ一覧)→ RETR n(n 番目を取得)→ DELE n(削除フラグ)→ QUIT(コミット)
削除は QUIT のときに 確定 される(セッション中はマーク扱い)。

walkthrough:ローカル POP3 サーバに接続する

テスト用 POP3 サーバ(Dovecot や GreenMail)を localhost:110 で起動してある前提です。alice / secret は事前に登録したテストユーザ。

$ telnet localhost 110
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
+OK Dovecot ready.

USER alice
+OK
PASS secret
+OK Logged in.

STAT
+OK 2 4096            ← メール 2 通、合計 4096 バイト

LIST
+OK 2 messages:
1 2048
2 2048
.                       ← LIST も「.」で終端

RETR 1
+OK 2048 octets
Subject: Hello via telnet
From: from@example.com
To: to@example.com
...
本文...
.                       ← 本文の終わりも「.」

DELE 1
+OK Marked to be deleted.

QUIT
+OK Logging out.
Connection closed by foreign host.

観察ポイント

現代では POP3 は減少: モバイル + マルチデバイス時代には「サーバから持ち帰って消す」モデルが合わず、IMAP(サーバ上にメールを残してフォルダ管理) が主流。さらに大手は TLS と現代的な認証(OAuth2 など) の組合わせが事実上必須(詳細は 第36回)。telnet で覗ける素の POP3 はもはや「歴史と原理を学ぶための教材」と思った方が実態に近い。

FTP を覗く ─ ポート 21(制御コネクション)

FTP の独特な点は、制御コネクション(21)データコネクション(20 か動的ポート)別々の TCP 接続 として張ること。telnet で覗けるのは 制御コネクション側だけ ですが、それでも USER/PASS/PWD/LIST のような対話は十分観察できます。第15回 FTP で学んだ Active / Passive モードの理解にも役立ちます。
POINT FTP 制御コネクションの基本:
USER → PASS → SYST(サーバ種別)→ PWD(現ディレクトリ)→ TYPE I(バイナリモード) → PASV(データコネクションの IP/Port を要求) → … → QUIT
レスポンスは HTTP/SMTP と同じく 3桁コード(220 ready / 331 user ok need pass / 230 logged in / 226 transfer ok)。

walkthrough:test.rebex.net(公式テストサーバ)に接続

Rebex の公開 FTP テストサーバは demo / password で読み取り専用ログインできます。

$ telnet test.rebex.net 21
Trying 195.144.107.198...
Connected to test.rebex.net.
Escape character is '^]'.
220 Welcome to test.rebex.net!

USER demo
331 Please specify the password.
PASS password
230 Login successful.

SYST
215 UNIX Type: L8
PWD
257 "/" is the current directory.

TYPE I
200 Switching to Binary mode.

PASV
227 Entering Passive Mode (195,144,107,198,229,57)
                       ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
                       IP=195.144.107.198 / Port=229*256+57=58681
                       (この IP:Port にデータコネクションを張る ── telnet では見えない)

QUIT
221 Goodbye.
Connection closed by foreign host.

観察ポイント

もっと詳しく:Active / Passive と NAT

Active モード(古典) は サーバ → クライアントへ データコネクションを張る ── クライアントが NAT の内側にいるとサーバから到達できない。Passive モード(現代の標準) は クライアント → サーバへ 張るので、NAT 越えしやすい。telnet で PASV を打って返ってくる IP:Port をメモすれば、別端末から nc <ip> <port> でデータ接続を擬似的に張ることもできます ── 制御 / データの分離が手で確認できる教材。

4 プロトコル比較 ─ 似ていて違う

ここまでで見てきた4プロトコルを横並びにすると、共通点と固有の癖がはっきりします。
項目 HTTP SMTP POP3 FTP
標準ポート8025(MTA間)/ 587(submission)11021(制御)/ 20(データ)
暗号版第36回 アプリ層プロトコルのセキュア化 でまとめて扱う(HTTPS / SMTPS / POP3S / IMAPS / FTPS / SFTP / STARTTLS)
状態ステートレス(1往復で完結)セッション(EHLO→DATA→QUIT)セッション(AUTH→TRANS→UPDATE)セッション(USER→PASS→…→QUIT)
応答形式3桁ステータス + ヘッダ + 本文3桁コード + 1行/複数行+OK / -ERR3桁コード + 1行/複数行
本文区切りContent-Length(または chunked)単独の「.」行単独の「.」行別 TCP 接続(データコネクション)
RFCRFC 9110, 9112(HTTP/1.1 系)RFC 5321RFC 1939RFC 959
現代運用いずれも TLS 化版や代替プロトコル(SFTP・OAuth2 など)に移行 ─ 詳細は 第36回

図の見方:本講で扱う4プロトコルは 「TCP 上のテキスト対話」 という同じ DNA を持ちながら、状態モデルや本文の区切り方に固有の進化を遂げてきた。共通点を押さえれば「初見のテキストプロトコル」も読み解けるようになる ── これが手で打って学ぶ最大の見返り。

Q. 4プロトコルの中で「本文の終わりを示す方法」が他と違うのはどれ?

何が見えなくなるか ─ telnet の限界

telnet で覗けるのは 「平文 TCP 上のテキストプロトコル」 だけ。現代のプロトコル進化はその外側に向かっており、見えなくなる領域が広がっています。
見えなくなる対象 理由 代替手段
TLS / SSH 越しの全プロトコルTCP の上に TLS や SSH が乗ると中身は暗号化されるTLS の仕組みは 第35回、TLS の中で各プロトコルを覗く方法は 第36回 で扱う
HTTP/2 / HTTP/3バイナリフレーム形式 + HPACK 圧縮 + 多重化curl -v --http2、Wireshark の HTTP/2 dissector、発展編 QUIC/HTTP3
DNSバイナリプロトコル(UDP/TCP どちらも)dig / nslookup第13回 参照
「見えるところ」を見ることに意味がある: 現代のプロトコルが暗号化・バイナリ化したのは パフォーマンスとセキュリティ のためで、進化として正しい方向です。ただし 「人間が読める形式で TCP の上に並んでいる」という古典の感覚 が腹落ちしていれば、暗号化された中身も 「平文だったらこう書いてあるはず」 と推測できる ── 見えないものを想像する地力が付くのがこの観察ハンズオンの本質的な学びです。

まとめと用語チェック

SUMMARY 1. HTTP・SMTP・POP3・FTP は 「TCP 上のテキスト対話」 という共通の DNA を持つ古典プロトコル
2. telnet で 80 / 25 / 110 / 21 番に接続すれば、ブラウザ・メーラ・FTP クライアントの会話を 1文字ずつ手で再現 できる
3. 行末は CRLF、ステータスは 3桁コード(POP3 だけ +OK/-ERR)、本文の区切り方はプロトコルごとに違う
4. SMTP / POP3 / FTP は パスワードが平文 ── 現代運用では TLS 化版や別プロトコルに置き換わっている(詳細は 第36回 アプリ層プロトコルのセキュア化)
5. HTTPS・HTTP/2・HTTP/3・DNS は telnet では覗けない(バイナリ化や暗号化のため)。TLS 越しを覗く方法は 第36回、HTTP/2 などのバイナリ系は 発展編
6. 「平文 TCP の古典プロトコル」を手で打った経験は、現代の暗号化されたプロトコルを読み解く 地力 として残る

用語チェック

用語1行説明
テキストプロトコルASCII 文字列で要求/応答を表現する古典的な形式。telnet で読める
CRLF行末コード \r\n。HTTP/SMTP/POP3/FTP すべての行区切り
3桁ステータスコード2xx成功 / 3xx中継 / 4xx一時失敗 / 5xx永続失敗の共通慣習
+OK / -ERRPOP3 独自の応答形式(RFC 1939)
EHLO / MAIL FROM / RCPT TO / DATASMTP のセッション必須コマンド
USER / PASS / RETR / DELE / QUITPOP3 の主要コマンド
USER / PASS / PWD / TYPE / PASV / QUITFTP 制御コネクションの主要コマンド
制御コネクション / データコネクションFTP の特徴。21 と 20(または動的) を別 TCP で張る
dot-stuffingSMTP/POP3 で本文中の . 始まり行を .. にエスケープする規則
TLS 化版(STARTTLS / openssl s_client / SMTPS / IMAPS / POP3S / FTPS / SFTP)の用語は 第36回 アプリ層プロトコルのセキュア化 で扱う
NEXT: 次回(第17回)から トランスポート層 に降りていきます。本講で telnet を使って覗いてきたアプリ層プロトコルは、すべて TCP の上に乗っていましたが、トランスポート層には UDP という対の選択肢もあり、DNS / DHCP / 動画配信などはこちらを使います。 第17回 トランスポート層の役割第18回 TCP第19回 UDP へ。なお「サーバ・クライアントは1つのプロセス」という OS 視点の整理は 発展編 第49回 ネットワークプログラミングとサーバの実体 で扱います。

確認問題

問1. 本講で扱った4プロトコル(HTTP / SMTP / POP3 / FTP)の共通点として最も適切なものを1つ選べ。

次の選択肢から最も適切なものを選択してください。
A. すべて UDP の上で動く軽量プロトコルである
B. すべて TCP 上のテキストプロトコルで、telnet で対話を観察できる
C. すべて応答に +OK / -ERR を使う
D. すべて HTTP/2 と同じバイナリフレーム形式を使う
正解:B
4 プロトコルとも TCP 上のテキストプロトコル。A は誤り(全部 TCP)、C は POP3 だけ(他は3桁コード)、D は明確に誤り(古典プロトコルはバイナリではなくテキスト)。

問2. SMTP セッションで DATA コマンド後の本文の終了を示すものとして最も適切なものを選べ。

次の選択肢から最も適切なものを選択してください。
A. END という文字列を1行で送る
B. QUIT コマンドを送る
C. .(ピリオド)1文字だけの行を送る(CRLF.CRLF)
D. Content-Length ヘッダで先にバイト数を宣言する
正解:C
RFC 5321 の規定どおり、本文終了は 単独の「.」行(CRLF.CRLF) で示す。本文中に . から始まる行を入れたい場合は .. にエスケープする(dot-stuffing)。D の Content-Length は HTTP の方式。

問3. FTP の PASV コマンドの応答 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2) から正しく Port を計算する式はどれか。

次の選択肢から最も適切なものを選択してください。
A. p1 + p2
B. p1 * 100 + p2
C. p2 * 256 + p1
D. p1 * 256 + p2
正解:D
ポート番号は 16 ビット(0〜65535) なので、上位8ビット(p1)と下位8ビット(p2)に分けて返す。p1 * 256 + p2 で復元する。NAT を越える際にこの値が「サーバ側 IP」を含むので NAT 越えが破綻しがち、というのが Active/Passive とは別の FTP の悩みどころ。

問4. POP3 で DELE 1 を実行した後、削除はいつ確定するか。

次の選択肢から最も適切なものを選択してください。
A. QUIT でセッションを正常終了したとき(UPDATE 状態への遷移)
B. DELE を実行したその瞬間に即座に削除される
C. サーバが +OK を返した瞬間
D. 次に RETR を実行したとき
正解:A
RFC 1939 の状態遷移では、DELE は TRANSACTION 状態で 削除フラグ を立てるだけで、QUIT による UPDATE 状態への遷移 で初めて確定する。途中で RSET を打てばロールバック可能 ── データベースの BEGIN/COMMIT/ROLLBACK と同じ発想。

問5. telnet で覗けないプロトコル(あるいは状況)として最も適切なものを選べ。

次の選択肢から最も適切なものを選択してください。
A. ローカル MailHog の SMTP(1025番)
B. example.com の HTTP(80番)
C. https://example.com(443番、TLS)越しの HTTP/2
D. test.rebex.net の FTP 制御コネクション(21番)
正解:C
C は TLS で暗号化されている上に HTTP/2 のバイナリフレーム なので、telnet では中身が解釈できない(暗号化バイト列がそのまま流れるだけ)。代替手段(TLS を解いて中身を覗くツール、HTTP/2 対応の curl 等) は TLS の前提が要るため 第36回 で扱う。A・B・D は本講で実際に扱った「telnet で覗ける」例。
← PREV
第15回 FTP(ファイル転送)
NEXT →
第17回 ポート番号とソケット