strace でsmtp の通信を覗いてみた

oktlinux,Ruby,SMTP,strace,通信

GWに引越しする予定のoktです。
こんばんわ。

今日は strace の使い方を軽く紹介してみます。

strace はシステムコールをトレースする事ができます。

あるプロセスが呼んでいるシステムコールの状況を見ることが主な使い方ですが
軽くネットワークアプリケーションの通信を覗きたいときにも重宝します。
tcpdumpだとフィルタがめんどくさいな~ とか思ったときに使ってます。

と、いうわけでタイトル通り、smtpの通信を覗いてみます。

クライアントはtelnetを使います。
サーバはちょうどいいので dummy-smtpd.rb を使います。

dummy-smtpd.rbを起動して、psコマンドからプロセスIDを調べます。
strace コマンドの -p オプションにプロセスIDを渡して準備完了です。
strace コマンドからdummy-smtpd.rbの起動を行うこともできますのでお好きな方で。

# ruby dummy-smtpd.rb &
# ps xa | grep "[r]uby dummy-smtpd.rb" | awk '{print $1}'
22100
# strace -p 22100
Process 22100 attached - interrupt to quit

これでdummy-smtpd.rbのシステムコールを覗くことができます。
プロセスがシステムコールを呼ぶと strace コマンドの出力にトレースしたものが表示されます。

クライアント側で、telnetでdummy-smtpd.rb に繋いでメールを送ってみます。

$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 welcome to dummy smtp server
EHLO localhost
250 OK
MAIL From: <hoge@example.org>
250 OK
RCPT To: <hoge-1@example.org>
250 OK
DATA
354 OK
To: <hoge-1@example.org>
From: <hoge@example.org>
Subject: test
 
test
.
250 OK
QUIT
221 OK

strace コマンドの出力はこんな感じになりました。
# strace -p 22100
Process 22100 attached - interrupt to quit
select(4, [3], [], [], NULL) = 1 (in [3])
accept(3, {sa_family=AF_INET, sin_port=htons(43232), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5
fcntl64(5, F_GETFL) = 0x2 (flags O_RDWR)
fstat64(5, {st_mode=S_IFSOCK|0777, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7ee0000
_llseek(5, 0, 0xbffd1644, SEEK_CUR) = -1 ESPIPE (Illegal seek)
fcntl64(5, F_GETFL) = 0x2 (flags O_RDWR)
fstat64(5, {st_mode=S_IFSOCK|0777, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7edf000
_llseek(5, 0, 0xbffd1644, SEEK_CUR) = -1 ESPIPE (Illegal seek)
select(7, [], [5], [], {0, 0}) = 1 (out [5], left {0, 0})
select(4, [3], [], [], {0, 0}) = 0 (Timeout)
write(5, "220 welcome to dummy smtp server"..., 33) = 33
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, "EHLO localhost \r\n", 1024) = 17
select(7, [3], [5], [], NULL) = 1 (out [5])
write(5, "250 OK\n", 7) = 7
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, "MAIL From: <hoge@example.org>\r\n", 1024) = 31
select(7, [3], [5], [], NULL) = 1 (out [5])
write(5, "250 OK\n", 7) = 7
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, "RCPT To: <hoge-1@example.org>\r\n", 1024) = 31
time(NULL) = 1240558677
stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=125, ...}) = 0
stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=125, ...}) = 0
stat64("/etc/localtime", {st_mode=S_IFREG|0644, st_size=125, ...}) = 0
send(4, "<14>Apr 24 16:37:57 dummy-smtpd["..., 73, MSG_NOSIGNAL) = 73
select(7, [3], [5], [], NULL) = 1 (out [5])
write(5, "250 OK\n", 7) = 7
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, "DATA\r\n", 1024) = 6
select(7, [3], [5], [], NULL) = 1 (out [5])
write(5, "354 OK\n", 7) = 7
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, "To: <hoge-1@example.org>\r\n", 1024) = 26
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, "From: <hoge@example.org>\r\nSubjec"..., 1024) = 50
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, ".\r\n", 1024) = 3
select(7, [3], [5], [], NULL) = 1 (out [5])
write(5, "250 OK\n", 7) = 7
select(6, [3 5], [], [], NULL) = 1 (in [5])
read(5, "QUIT\r\n", 1024) = 6
select(7, [3], [5], [], NULL) = 1 (out [5])
write(5, "221 OK\n", 7) = 7
close(5) = 0
munmap(0xb7edf000, 4096) = 0
close(5) = -1 EBADF (Bad file descriptor)
munmap(0xb7ee0000, 4096) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8 ) = 0

こんな感じで、 strace で観察しているdummy-smtpd.rbから見た
socket へのwriteとreadの内容が見えます。

-s オプションで表示サイズを変えるとメールの文面が全部見えますのでおためしアレ。

oktlinux,Ruby,SMTP,strace,通信

Posted by okt