Akira's Tech Notes

Java/JVM | GNU/Linux | Emacs/Lisp | 知的好奇心駆動

header-icon
ネイティブでない日本語で思い付くことや気になることをダラダラ書く、体裁とかは気にしない。読みづらいと感じた時に随時更新する。

[検証]SMTPプロトコール監視してみた

自宅のPC環境にMTA(postfix)サーバを構築しました。 1周間ほど保持したので、telnet、nc、tcpdumpコマンドから メール送信処理の中身を観測してみたいと思います。

1 概要

VM環境を立てるのが面倒のため、loopbackインタフェースを通して ローカル環境内で検証を行う。

+--------------+         +-------------+
|              |         |             |
| クライアント +-- lo ----+  MTAサーバ |
|              |         |             |
+--------------+         +-------------+
  127.0.0.1                127.0.0.1:25

ドメイン、メール送受信情報

MTAサーバFQDN mail.home
クライアントFQDN jizai.home
送信者メール akira@mail.home
受信者メール root@mail.home

tcpdumpコマンドでloopbackインタフェースのパケットを監視する。

[akira@jizai ~]$ sudo tcpdump -n  -i lo port 25

telnetからメール送信レシピ、 が付いている部分が手入力

[akira@jizai ~]$ telnet localhost 25     ★接続開始
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.home ESMTP unknown
HELO jizai.home                          ★メール送信開始宣言
250 mail.home
MAIL FROM: <akira@mail.home>             ★送信元を指定する
250 2.1.0 Ok
RCPT TO: <root@mail.home>                ★送信先を指定する
250 2.1.5 Ok
DATA                                     ★メール本文を開始する
354 End data with <CR><LF>.<CR><LF>
This is a Test mail from telnet
Hello root!
.                                        ★メール本文終了
250 2.0.0 Ok: queued as AB9BF8A107E
quit                                     ★接続終了
221 2.0.0 Bye
Connection closed by foreign host.
[akira@jizai ~]$

2 telnetからの接続開始

localhostの25番ポートへ接続する。

[akira@jizai ~]$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.home ESMTP unknown    ★ 説明:MTAサーバから準備完了応答メッセージ

tcpdumpの出力にtcpの3ウェイ・ハンドシェイク処理(1-3行目)と MTAサーバから最初の応答メッセージ(4-5行目)が表示される。

11:49:33.684755 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [S], seq 1483942186, win 43690, options [mss 65495,sackOK,TS val 2064872 ecr 0,nop,wscale 7], length 0
11:49:33.684770 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [S.], seq 2082428713, ack 1483942187, win 43690, options [mss 65495,sackOK,TS val 2064872 ecr 2064872,nop,wscale 7], length 0
11:49:33.684787 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [.], ack 1, win 342, options [nop,nop,TS val 2064872 ecr 2064872], length 0
11:49:33.685184 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [P.], seq 1:30, ack 1, win 342, options [nop,nop,TS val 2064872 ecr 2064872], length 29
11:49:33.685214 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [.], ack 30, win 342, options [nop,nop,TS val 2064872 ecr 2064872], length 0

気になること、tcpdumpの出力に途中からシーケンス番号が1に変わった。調べてみた結果、 tcpdump がわかりやすく表示するためでした。 -S を付けることでオリジナルのシーケンス 番号をそのまま出力することができる。

MTAログにクライアントからの接続跡が記録された。

Jun 13 11:49:33 localhost postfix/smtpd[4873]: warning: hostname jizai does not resolve to address 192.168.100.3
Jun 13 11:49:33 localhost postfix/smtpd[4873]: connect from unknown[192.168.100.3]

MTAサーバでHELOからの名前解決にまだ問題が残っているようです。 DNSサーバに名前登録したはずです。さあ、どうしよう!

3 メール送信の開始を宣言する

HELO <クライアントのホスト名> コマンドでメールサーバに にてメール送信の開始を宣言する。

[akira@jizai ~]$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.home ESMTP unknown
HELO jizai.home        ★ HELOコマンド実行
250 mail.home          ★ サーバからの250応答

tcpdumpの出力、クライアントのPUSH(1行目)とサーバのACK(2行目)、 そしてサーバから応答時のPUSHとクライアントの受信ACKで合計4通が表示された。

10:51:18.385531 IP 127.0.0.1.55748 > 127.0.0.1.25: Flags [P.], seq 1:18, ack 30, win 342, options [nop,nop,TS val 1016282 ecr 1012424], length 17
10:51:18.385568 IP 127.0.0.1.25 > 127.0.0.1.55748: Flags [.], ack 18, win 342, options [nop,nop,TS val 1016282 ecr 1016282], length 0
10:51:18.385682 IP 127.0.0.1.25 > 127.0.0.1.55748: Flags [P.], seq 30:45, ack 18, win 342, options [nop,nop,TS val 1016282 ecr 1016282], length 15
10:51:18.385711 IP 127.0.0.1.55748 > 127.0.0.1.25: Flags [.], ack 45, win 342, options [nop,nop,TS val 1016282 ecr 1016282], length 0

4 送信元を指定する

MAIL FROM: <送信元メール> コマンドにて送信元メールアドレスを設定する。

MAIL FROM: <akira@mail.home>
250 2.1.0 Ok       ★応答コード 250

tcpdumpの出力、サーバからのACKと応答メッセージのPUSHが纏めて送信されたため TCPやり取りが3通で表示された。

11:50:09.768768 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [P.], seq 18:48, ack 45, win 342, options [nop,nop,TS val 2075697 ecr 2070308], length 30
11:50:09.768944 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [P.], seq 45:59, ack 48, win 342, options [nop,nop,TS val 2075697 ecr 2075697], length 14
11:50:09.768976 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [.], ack 59, win 342, options [nop,nop,TS val 2075697 ecr 2075697], length 0

5 送信先を指定する

RCPT TO: <送信先メール> コマンドにて送信先メールアドレスを設定する。

MAIL FROM: <root@mail.home>
250 2.1.5 Ok     ★応答コード 250

tcpdumpの出力、サーバからのACKと応答メッセージのPUSHが纏めて送信されたため TCPやり取りが3通で表示された。

11:50:22.696751 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [P.], seq 48:75, ack 59, win 342, options [nop,nop,TS val 2079575 ecr 2075697], length 27
11:50:22.703097 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [P.], seq 59:73, ack 75, win 342, options [nop,nop,TS val 2079577 ecr 2079575], length 14
11:50:22.703135 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [.], ack 73, win 342, options [nop,nop,TS val 2079577 ecr 2079577], length 0

また RCPT TO コマンドがMTAサーバに届くと、サーバ側のsmtpdプロセスでメール キューイングIDの払出、送信先アドレスのチェック処理が実施される。以下はMTAログです。

Jun 13 11:50:22 localhost postfix/smtpd[4873]: AB9BF8A107E: client=unknown[192.168.100.3]

6 メール本文を開始する

DATA コマンドにてメール本文開始要求をサーバへ送信する。

DATA
354 End data with <CR><LF>.<CR><LF>  ★応答コード 354

tcpdumpの出力

11:50:44.461274 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [P.], seq 75:81, ack 73, win 342, options [nop,nop,TS val 2086105 ecr 2079577], length 6
11:50:44.461442 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [P.], seq 73:110, ack 81, win 342, options [nop,nop,TS val 2086105 ecr 2086105], length 37
11:50:44.461474 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [.], ack 110, win 342, options [nop,nop,TS val 2086105 ecr 2086105], length 0

telnetターミナルからメール本文を入力する、観測結果から見ると改行が入力されるたびに 入力されたテキストがサーバへ送信される。

This is a Test mail from telnet       ★改行1
Hello root!                           ★改行2

tcpdumpの出力

★改行1
11:50:58.590306 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [P.], seq 81:114, ack 110, win 342, options [nop,nop,TS val 2090343 ecr 2086105], length 33
11:50:58.628041 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [.], ack 114, win 342, options [nop,nop,TS val 2090355 ecr 2090343], length 0

★改行2
11:51:09.655315 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [P.], seq 114:127, ack 110, win 342, options [nop,nop,TS val 2093663 ecr 2090355], length 13
11:51:09.655352 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [.], ack 127, win 342, options [nop,nop,TS val 2093663 ecr 2093663], length 0

7 メール本文終了

.(ピリオド)を入力して、メール本文終了要求をサーバへ送信する。

.
250 2.0.0 Ok: queued as AB9BF8A107E

.(ピリオド)の送信とサーバからの250正常応答受信合計4通。

11:51:21.982567 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [P.], seq 127:130, ack 110, win 342, options [nop,nop,TS val 2097361 ecr 2093663], length 3
11:51:21.982599 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [.], ack 130, win 342, options [nop,nop,TS val 2097361 ecr 2097361], length 0
11:51:22.014030 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [P.], seq 110:147, ack 130, win 342, options [nop,nop,TS val 2097370 ecr 2097361], length 37
11:51:22.014070 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [.], ack 147, win 342, options [nop,nop,TS val 2097370 ecr 2097370], length 0

MTAログにメールのキューイング処理と転送処理の記録が出力された。 メールヘッダのmessage-id項目がこの時点で払いだされたようです。

  • 形式: yyyymmdd999999.キューイングID@ドメイン名
Jun 13 11:51:21 localhost postfix/cleanup[5028]: AB9BF8A107E: message-id=<20140613025022.AB9BF8A107E@mail.home>
Jun 13 11:51:22 localhost postfix/qmgr[920]: AB9BF8A107E: from=<akira@mail.home>, size=333, nrcpt=1 (queue active)
Jun 13 11:51:22 localhost postfix/local[5058]: AB9BF8A107E: to=<akira@mail.home>, orig_to=<root@mail.home>, relay=local, delay=72, delays=72/0.01/0/0.02, dsn=2.0.0, status=sent (delivered to maildir)
Jun 13 11:51:22 localhost postfix/qmgr[920]: AB9BF8A107E: removed

8 接続終了

quit コマンドにて接続切断する。

quit                 ★ 切断送信
221 2.0.0 Bye        ★ 211応答
Connection closed by foreign host.
★ 切断送信
11:51:42.503665 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [P.], seq 130:136, ack 147, win 342, options [nop,nop,TS val 2103517 ecr 2097370], length 6

★ 211応答
11:51:42.503825 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [P.], seq 147:162, ack 136, win 342, options [nop,nop,TS val 2103517 ecr 2103517], length 15
11:51:42.503856 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [.], ack 162, win 342, options [nop,nop,TS val 2103517 ecr 2103517], length 0

★ tcpセッション終了
11:51:42.503867 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [F.], seq 162, ack 136, win 342, options [nop,nop,TS val 2103517 ecr 2103517], length 0
11:51:42.503969 IP 192.168.100.3.30760 > 192.168.100.3.25: Flags [F.], seq 136, ack 163, win 342, options [nop,nop,TS val 2103517 ecr 2103517], length 0
11:51:42.503999 IP 192.168.100.3.25 > 192.168.100.3.30760: Flags [.], ack 137, win 342, options [nop,nop,TS val 2103517 ecr 2103517], length 0

MTAログにクライアント切断跡が残ります。

Jun 13 11:51:42 localhost postfix/smtpd[4873]: disconnect from unknown[192.168.100.3]

9 ncコマンドでファイルからメール送信テスト

telnetで入力した内容を sendmail_test.txt に保存し、ncに渡せばコマン1行 でメール送信することができた。

sendmail_test.txt の内容。

HELO jizai.home
MAIL FROM: <akira@mail.home>
RCPT TO: <root@mail.home>
DATA
This is a Test mail from nc
Hello root!
.

メール送信したみた。

[akira@jizai temp]$ cat sendmail_test.txt | nc localhost 25
220 mail.home ESMTP unknown
250 mail.home
250 2.1.0 Ok
250 2.1.5 Ok
354 End data with <CR><LF>.<CR><LF>
250 2.0.0 Ok: queued as BE5B98A107E
[akira@jizai temp]$

10 習ったこと

  • tcpdumpのシーケンス番号の出力ルール
  • DATAブロック内であっても、telnetターミナルで改行すると内容がサーバに送信される
  • キューイングIDとメールメッセージIDの払出タイミング

Comments