メール」カテゴリーアーカイブ

メールに関すること

openssl s_client で SMTP STARTTLS と SMTP AUTH を動作確認する

概要: openssl s_client コマンドについて

telnet コマンドで HTTP や SMTP、POP の接続テストを行うことがあるが、同様に openssl の s_client サブコマンドで、TLS 接続の手動確認をすることが可能だ。例えば、HTTPS の確認は以下のように実行できる。

$ openssl s_client -connect www.example.com:443
(中略)
GET / HTTP/1.0(Enter)
Host: www.example.com(Enter2回押す)

さらに、最初は平文接続して、アプリケーションプロトコル上の STARTTLS コマンドで TLS 状態に入りたい場合もある。SMTP、IMAP、LDAP、FTP などの STARTTLS が相当する。これも s_client サブコマンドの -starttls オプションで実現できる。

mail.example.com サーバの TCPポート 587 (SMTP Submission) で SMTP STARTTLS が使える場合、以下のコマンドで接続が可能となる。-starttls オプションの引数に、smtp をとる。

$ openssl s_client -connect mail.example.com:587 -starttls smtp

ただし、SMTP セッションの中で RCPT TO: を大文字で打った瞬間に、RENEGOTIATING という表示とともに先へ進めなくなってしまうので注意が必要である。

$ openssl s_client -connect mail.example.com:587 -starttls smtp
CONNECTED(00000003)
depth=2 C = JP, O = "SECOM Trust Systems CO.,LTD.", OU = Security Communication RootCA2
verify return:1
depth=1 C = JP, L = Academe, O = National Institute of Informatics, CN = NII Open Domain CA - G4
verify return:1
depth=0 C = JP, L = Academe, O = Example, OU = Example Dept, CN = mail.example.com
verify return:1
(中略)
250 DSN
EHLO mail.example.com
250-mail.example.com
250-PIPELINING
250-SIZE 52428800
250-ETRN
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
MAIL FROM: test@example.com
250 2.1.0 Ok
RCPT TO: test@example.jp
RENEGOTIATING
depth=2 C = JP, O = "SECOM Trust Systems CO.,LTD.", OU = Security Communication RootCA2
verify return:1
depth=1 C = JP, L = Academe, O = National Institute of Informatics, CN = NII Open Domain CA - G4
verify return:1
depth=0 C = JP, L = Academe, O = Example, OU = Example Dept, CN = mail.example.com
verify return:1

標準入力の一文字目が大文字の「R」になっていると、openssl s_client の TLS 再ネゴシエーションコマンドとして解釈されてしまうためである。

再ネゴシエーションを回避するには、先頭の r を小文字で打つか、openssl s_client のオプションとして -ign_eof または -quiet を追加する。

$ openssl s_client -quiet -connect mail.example.com:587 -starttls smtp

SMTP AUTH のテスト

上記の openssl s_client コマンドを用いて、SMTP のセッションを手打ちで再現テストする。さらに SMTP セッションの中で、SMTP AUTH のテストも組み込んでみる。

実行例1: AUTH PLAIN 認証

SMTP AUTH の PLAIN コマンドで必要な文字列は、「ユーザ名\0ユーザ名\0パスワード」(\0はヌル文字)という合成文字列を BASE64 エンコードしたものである。あらかじめ文字列を作っておく。

$ printf 'username\0username\0password' | base64
dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcmQ=

さきほどのエンコード文字列を AUTH PLAIN の引数として与える。

$ openssl s_client -quiet -connect mail.example.com:587 -starttls smtp
depth=2 C = JP, O = "SECOM Trust Systems CO.,LTD.", OU = Security Communication RootCA2
verify return:1
depth=1 C = JP, L = Academe, O = National Institute of Informatics, CN = NII Open Domain CA - G4
verify return:1
depth=0 C = JP, L = Academe, O = Example, OU = Example Dept, CN = mail.example.com
verify return:1
250 DSN
EHLO mail.example.com
250-mail.example.com
250-PIPELINING
250-SIZE 10485760
250-ETRN
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN dXNlcm5hbWUAdXNlcm5hbWUAcGFzc3dvcmQ=
235 2.7.0 Authentication successful ←認証成功
MAIL FROM: test@example.com
250 2.1.0 Ok
RCPT TO: test@example.jp
250 2.1.5 Ok ←メールリレー成功
QUIT
221 2.0.0 Bye

実行例2: AUTH LOGIN 認証

AUTH LOGIN コマンドでは、ユーザ名とパスワードをそれぞれ BASE64 エンコードした文字列が必要になる。

$ printf 'username' | base64
dXNlcm5hbWU=
$ printf 'password' | base64
cGFzc3dvcmQ=

サーバからの 334 VXNlcm5hbWU6 に対してはユーザ名のエンコード文字列を、334 UGFzc3dvcmQ6 に対してはパスワードのエンコード文字列を入力する。

$ openssl s_client -quiet -connect mail.example.com:587 -starttls smtp
depth=2 C = JP, O = "SECOM Trust Systems CO.,LTD.", OU = Security Communication RootCA2
verify return:1
depth=1 C = JP, L = Academe, O = National Institute of Informatics, CN = NII Open Domain CA - G4
verify return:1
depth=0 C = JP, L = Academe, O = Example, OU = Example Dept, CN = mail.example.com
verify return:1
250 DSN
EHLO mail.example.com
250-mail.example.com
250-PIPELINING
250-SIZE 10485760
250-ETRN
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH LOGIN
334 VXNlcm5hbWU6 ←"Username:" が BASE64 エンコードされている
dXNlcm5hbWU=
334 UGFzc3dvcmQ6 ←"Password:" が BASE64 エンコードされている
cGFzc3dvcmQ=
235 2.7.0 Authentication successful ←認証成功
MAIL FROM: test@example.com
250 2.1.0 Ok
RCPT TO: test@example.jp
250 2.1.5 Ok ←メールリレー成功
QUIT
221 2.0.0 Bye

参考URL:

Exchange Server が正常終了しなかった場合のデータベース復旧

Exchange Server の入ったサーバが、OSごと固まったり、ハードウェアトラブルで停止した場合の復旧方法を考えてみる。

ひとまずOSを立ち上げなおすことが出来たとして、Exchange Server を起動しようとするとデータベースが dirty shutdown 状態となっており、マウントできない場合がある。

こういう場合にマイクロソフトの提供している手順ドキュメントがあるのだが…
修復済みの Exchange データベースのサポート ポリシーの変更

上記ドキュメントの手順3を進める前にデータベースをマウントする必要がある。しかし手順1、2でデータベースを掃除したにもかかわらず、それでもマウントできないということもある。

実行例:

[PS] C:\Windows\system32> Mount-Database -Identity MailboxDB01 -force
データベース "MailboxDB01" をマウントできませんでした。エラー: Active Manager
 の操作に失敗しました。エラー: データベース操作が失敗しました。エラー:
 操作が失敗し、メッセージが生成されました:
 MapiExceptionDatabaseError: Unable to mount database. (hr=0x80004005, ec=1108)
Diagnostic context:
...

そういう場合はトランザクションログが壊れている可能性が高いので、ログファイルを削除(退避)するとよい。

トランザクションログファイルの状態を示すコマンドとして、eseutil /ml コマンドがある。

[PS] C:\Windows\system32> eseutil /ml D:\Exchange\MailboxDB01\E00

これで壊れているログファイルがどれなのかわかるが、ともかくデータベースと同一ディレクトリにある拡張子.logのファイル(拡張子を隠す設定になっていたら表示すること!)をすべて別フォルダに退避してからマウントコマンドを実行するとよい。

[PS] C:\Windows\system32> D:
[PS] D:\> cd \Exchange\MailboxDB01
[PS] D:\Exchange\MailboxDB01> mkdir backup
[PS] D:\Exchange\MailboxDB01> move *.log backup
[PS] D:\Exchange\MailboxDB01> Mount-Database -Identity MailboxDB01 -force

Postfixのsender_canonical_mapsでヘッダを書きかえてくれない

sender_canonical_mapsを設定したけど、エンベロープ From は書き換わってもヘッダ From が書き換わらない!という場合がある。sender_canonical_classes にもちゃんと header_sender が含まれている(デフォルト)のに書き換わらない。

結論から言うと、local_header_rewrite_clients の設定を見直す必要がある。

デフォルトでは

local_header_rewrite_clients = permit_inet_interfaces

となっていて、サーバのローカルから送信されたメールのみ、ヘッダも書き換えるという動作をする。つまり、メールハブでいくらsender_canonical_maps を設定しても、他サーバから送信されたメールのヘッダ From は書き換えてくれないのだ。

自分が管理しているドメイン(組織内ローカルネットワーク)のどのクライアント・サーバから送られたメールでも From ヘッダを書き換え対象としたい場合、管理対象ドメインの IP アドレスを mynetworks に列挙した上で以下を設定する。

local_header_rewrite_clients = permit_mynetworks

難しく考えず、書き換え対象なら必ず書き換える!という場合は以下の設定を入れる。

local_header_rewrite_clients = static:all

この場合、書き換えテーブルにマッチすれば、インバウンドメールであろうと書き換えが入ることになるが、まあそれほど問題はないだろう。

参考:

Postfixで送信者(From:)によってルーティングを変更する

メールのエンベロープ From: を見て、次のリレー先 SMTP サーバを変更するような設定をしたい。例えば、組織内の foo@example.com からのメールは送信リレーサーバ1へ、bar@example.com からのメールは送信リレーサーバ2へ振り分けるといった設定を行いたい。

利用例としては、ライセンス数制限のあるメールセキュリティアプライアンスを、一部のユーザに対してだけ適用したい場合に使う。他にも、大学などで教職員ユーザはセキュリティポリシー緩めのメールサーバへ、学生は厳しめのサーバへ転送したいなど、応用方法は様々。

設定項目としては、sender_dependent_default_transport_maps と sender_dependent_relayhost_maps がある。どちらを使っても同等の動作を実現できるが、少し書式が異なる。

1. sender_dependent_default_transport_maps を使う場合

/etc/postfix/main.cf:

sender_dependent_default_transport_maps = hash:/etc/postfix/sender_dependent_transport

/etc/postfix/sender_dependent_transport:

@example.co.jp            smtp:[リレーサーバ1]:25
@sub.example.co.jp        smtp:[リレーサーバ2]:25

メールの送信者が foo@example.co.jp の場合はリレーサーバ1に、bar@sub.example.co.jp の場合はリレーサーバ2に送られる。

この設定は、default_transport (デフォルト値: smtp) をエンベロープ From: 次第で上書き変更するというものである。上記のような書き方もできるし、master.cf で別の transport を定義しておき右辺に使うことも可能。

2. sender_dependent_relayhost_maps を使う場合

/etc/postfix/main.cf:

sender_dependent_relayhost_maps = hash:/etc/postfix/sender_dependent_relayhost

/etc/postfix/sender_dependent_relayhost:

@example.co.jp           [リレーサーバ1]:25
@sub.example.co.jp       [リレーサーバ2]:25

これは relayhost の設定を From: 次第で上書きするという機能なので、テーブルの右辺は relayhost を書くときの形式でなければならない。つまり、 transport:host:port の形式ではなく、host:port だけの形式となる。

ただし、「この情報は relay_transport、default_transport および transport(5) テーブルで上書きされます。」とのことなので、transportテーブルを併用する場合は思った通りに動作しないかもしれない。

milter-greylist で GeoIP を使えるようにする

※以下は古い記事です。Ubuntu 16.04 以降では libGeoIP がリンクされているため、必要ありません。

Ubuntu 14.04 標準パッケージの milter-greylist は libGeoIP をリンクするようにコンパイルされていないので、GeoIP (IPアドレスベースの国別判定) をポリシーに利用することが出来ない。そこで Ubuntu ソースパッケージを微修正してリビルドすることで GeoIP を使えるようにする。また、ついでにPostfixへの対応を入れておく。

必要なパッケージのインストール

myserver1:~$ sudo apt-get install build-essential quilt debhelper autotools-dev bison flex
myserver1:~$ sudo apt-get install libgeoip-dev libspf2-dev libmilter-dev

ソースパッケージのダウンロード

myserver1:~$ apt-get source milter-greylist

パッケージ情報ファイルの編集

GeoIP をリンクするように、パッケージ情報ファイルを編集する。

rules ファイルを編集し、configure オプションの中に –with-libGeoIP \ を追加する。configure 実行時に libGeoIP を探してくれるようになる。

myserver1:~$ cd milter-greylist-4.3.9
myserver1:milter-greylist-4.3.9$ vi debian/rules
override_dh_auto_configure:
    dh_auto_configure -- \
    --with-user=greylist \
    --sysconfdir=/etc/milter-greylist \
    --with-conffile=/etc/milter-greylist/greylist.conf \
    --with-dumpfile=/var/lib/milter-greylist/greylist.db \
    --with-libspf2=/usr \
    --with-libmilter=/usr \
    --with-libGeoIP \  ←ここを追加
    --enable-postfix \  ←ここを追加
    --enable-dnsrbl \
    --disable-rpath \
    LDFLAGS=" -Wl,-z,defs -L/usr/lib/libmilter " \
    CFLAGS=" -fno-strict-aliasing "

また、controlファイルを編集して、Build-Depends 行に libgeoip-dev を追加する。

myserver1:milter-greylist-4.3.9$ vi debian/control
Build-Depends: quilt, debhelper (>= 8), autotools-dev, libmilter-dev, bison, flex, libspf2-dev, libgeoip-dev

パッケージバージョン番号を変更するために、changelogも編集する。内容は適当。

myserver1:milter-greylist-4.3.9$ vi debian/changelog
milter-greylist (4.3.9-101) unstable; urgency=low

  * Build with --with-libGeoIP
  * Build with --enable-postfix

 -- My Name <myname@example.com>  Mon, 30 Jun 2014 10:00:00 +0900

バージョン番号を元のパッケージより大きくしておかないと、apt-get upgrade した時に公式パッケージで置き換えられてしまう。ここでは 4.3.9-1 から 4.3.9-101 にしておいた。

ビルド

編集が終わったら、実際にビルドする。

myserver1:milter-greylist-4.3.9$ dpkg-buildpackage -us -uc

インストール

.deb パッケージが出来上がったら、公式パッケージをアンインストールして入れ換える。

myserver1:milter-greylist-4.3.9$ sudo apt-get purge milter-greylist
myserver1:milter-greylist-4.3.9$ sudo dpkg -i ../milter-greylist_4.3.9-101_amd64.deb

設定

milter-greylist を入れ換えたら、/etc/milter-greylist/greylist.conf に geoip の記述が使えるようになる。例えば自宅のサーバでは、CN からメールを受け取る予定が無いのでこれをブラックリストに入れてみる。

myserver1:~$ sudo vi /etc/milter-greylist/greylist.conf

greylist.conf の中身:

geoipdb "/usr/share/GeoIP/GeoIP.dat"
...
racl blacklist geoip "CN"

Ubuntu のパッケージリビルド (Ubuntu 14.04 LTS に milter-manager をインストール)

※以下は古い内容です。既に Ubuntu 14.04 用 milter manager パッケージが配布されています。

Ubuntu 14.04 が出たのでさっそくサーバを置き換えようとしたのだけれど、milter-managerのパッケージがまだ用意されていないので、saucyのファイルを借りてパッケージをリビルドしてみた記録。

1. 下準備

ビルド環境に必須なパッケージと、milter-managerがビルド依存するパッケージをインストールする。

$ sudo apt-get install build-essential debhelper
$ sudo apt-get install libglib2.0-dev ruby1.9.1-dev cdbs

2. 13.10 (saucy) 用ファイルのダウンロード


$ wget http://jaist.dl.sourceforge.net/project/milter-manager/ubuntu/stable/pool/saucy/universe/m/milter-manager/milter-manager_2.0.2-1.diff.gz
$ wget http://jaist.dl.sourceforge.net/project/milter-manager/ubuntu/stable/pool/saucy/universe/m/milter-manager/milter-manager_2.0.2-1.dsc
$ wget http://jaist.dl.sourceforge.net/project/milter-manager/ubuntu/stable/pool/saucy/universe/m/milter-manager/milter-manager_2.0.2.orig.tar.gz

3. ビルド

saucy用のパッケージファイルから、特に何の変更もしなくてもビルドできた。

$ tar xzf milter-manager_2.0.2.orig.tar.gz
$ cd milter-manager-2.0.2
$ gzip -cd ../milter-manager_2.0.2-1.diff.gz | patch -p1
$ dpkg-source --before-build .
$ dpkg-buildpackage -us -uc

4. インストール

dpkgコマンドでインストールする。

$ cd ..
$ sudo dpkg -i libmilter-client0_2.0.2-1_amd64.deb libmilter-core0_2.0.2-1_amd64.deb libmilter-manager0_2.0.2-1_amd64.deb libmilter-server0_2.0.2-1_amd64.deb milter-manager_2.0.2-1_amd64.deb ruby-milter-client_2.0.2-1_amd64.deb ruby-milter-core_2.0.2-1_amd64.deb ruby-milter-server_2.0.2-1_amd64.deb

※アンインストールしたい場合は以下の通り。

$ sudo apt-get purge libmilter-client0 libmilter-core0 libmilter-manager0 libmilter-server0 milter-manager ruby-milter-client ruby-milter-core ruby-milter-server

※ローカル .deb ファイルを apt-get コマンドでインストールしたい場合は、以下のページを参考に。
ローカルに置いたdebファイルをapt-get installでインストールする

手っ取り早くbase64エンコードしたい

nkf の -M オプションは、先に変換が入るためバイナリファイルのエンコードには使えない。nkfはテキストメール前提なので、JIS(ISO-2022-JP)にいったん変換してからエンコードするということらしい。
バイナリファイルを nkf -MB でエンコードして nkf -mB で戻すと全然違うファイルが出来上がる。


$ nkf -MB < 1.zip > 1.b64
$ nkf -mB < 1.b64 > 2.zip
$ md5 1.zip 2.zip
MD5 (1.zip) = 42558acff029a174684f9cf3772c9847
MD5 (2.zip) = 288077e040f5787d3767c72956ae6bf2

nkfではなく、base64コマンドを使うことできちんとエンコードできる。

$ base64 -b 72 < 1.zip > 1.b64
$ base64 -D 1.b64 > 2.zip
$ md5 1.zip 2.zip
MD5 (1.zip) = 42558acff029a174684f9cf3772c9847
MD5 (2.zip) = 42558acff029a174684f9cf3772c9847

上記はMac OS Xのシェル上で実行した結果。
Linux(GNU coreutils)のbase64コマンドは、デコードオプションが -D ではなく -d なので注意。