投稿ポートから SMTP ポートへのフォールバック
山本和彦
IIJ 技術研究所
執筆 2005年11月9日
更新 2006年1月20日
概要
迷惑メールの問題を解決するために、 メールリーダがメールを送信する際は、 現在利用されている SMTP ポート(25番)ではなく、 投稿ポート(587番)を利用することが望まれている。 ここでは、メールリーダの送信時の動作を 「最初に投稿ポートの利用を試み、 接続できない場合は SMTP ポートへ接続する」よう変更することを提案する。 また、その変更はユーザから見た操作性にはほとんど影響を与えないことを示す。
背景
迷惑メール配送業者は、 Bot(ゾンビ)を使ったり、 規制の甘い ISP を渡り歩いたりして、 PC から目標とするメールサーバに直接 SMTP コネクションを張り、 メールを送信する。 これを繰り返すことによって、大量の迷惑メールをばらまく。
この対策として、 境界で上り方向の SMTP ポートを遮断する ISP が増えてきた。 この対策は、OP25B (Outbound Port 25 Blocking)と呼ばれることもある。
OP25B 対策を実施した ISP は、もちろん、 その ISP の送信サーバから他の ISP の受信サーバへ、 25番ポートを使い SMTP コネクションを確立できるように設定する。 このような環境では、ISP のユーザは、ISP の送信サーバを使う限り、 メールの送信に問題は生じない。
しかしながら、他の ISP にも正式にアカウントを持ち、 他の ISP の送信サーバを利用してメールを送信するユーザもいる。 この通信は、迷惑メール配送業者のと同様に遮断される。 このユーザを救うために、投稿と配送の分離が提案されている。 投稿とはメールリーダから送信サーバへメールを配送することであり、 配送とは送信サーバから受信サーバへメールを届けることである。
投稿も配送もプロトコルとしては、これまで通り SMTP を使う。 投稿は、OP25B に遮断されないように、 投稿(Submission; RFC2476)ポートである 587 番を使う。 一方、配送はこれまで通り SMTP ポートである 25 番を使う。
ポート番号を 25 から 587 へ変えただけでは、 迷惑メール配送業者もそれを使うようになるだろう。 そこで、投稿ポートでは必ずユーザ認証(SMTP AUTH)を要求しなければならない。 また、配送に対しドメイン認証の技術が普及すれば、 メールアドレスを詐称できない環境が整うことになる (下の図を参照のこと)。 詳しくは、 メールアドレスの詐称を防止する「ドメイン認証」を参照されたい。
現時、投稿ポートを提供する ISP は増加している。 一方で、デフォルトで投稿ポートを利用するメールリーダは皆無である。
課題
現在、多くのメールリーダが、 メールを送信する際に使うポートを変更可能である。 しかし、ユーザが自分で変更しなければならない現状では、 投稿ポートの普及速度は遅いであろう。 投稿ポートを早く普及させるためには、 メールリーダがデフォルトで投稿ポートを利用するようになることが望まれている。
しかしながら、デフォルトのポートを単純に投稿ポートに設定してリリースすると、 送信サーバが投稿ポートでメールを受け付けてない場合、 メールの送信に失敗するという問題が起こる。
フォールバックとその技術考察
上記の課題を解決するために、 まず投稿ポートの利用を試み、 利用できない場合は SMTP ポートへフォールバックするという方法を提案する。
以下、場合を分けて動作を説明する。
1) 投稿ポートが提供されている場合
何も問題がない。 OP25B の環境では、断然有利である。
2) TCP RST が返る場合
RTT の時間だけ待たされて、SMTP ポートへフォールバックする。 ユーザにはほとんど分からない。 多くの ISP が、このケースであると思われる。
3) ICMP ハードエラーが返る場合
RTT の時間だけ待たされて、SMTP ポートへフォールバックする。 ユーザにはほとんど分からない。 ファイアウォールでフィルタリングされている場合に起こりうる。
ちなみに、ハードエラーは以下の通り:
- ICMPv4 Destination Unreachable
- コード 2 = protocol unreachable
- コード 3 = port unreachable
- コード 4 = fragmentation needed and DF set
- コード 6 = destination network unknown
- コード 7 = destination host unknown
- コード 8 = source host isolated
- コード 9 = communication with destination network administratively prohibited
- コード 10 = communication with destination host administratively prohibited
- コード 11 = network unreachable for type of service
- コード 12 = host unreachable for type of service
- ICMPv6 Destination Unreachable
- コード 1 = communication with destination administratively prohibited
- コード 4 = port unreachable
4) ICMP ソフトエラーが返る場合
ICMP ソフトエラーは、経路制御の問題から引き起こされる。 経路制御の問題が起こっているときは、 通信が不可能である。 投稿ポートを先に試すか否かに関わらず、 通信が不可能であることに変わりはない。 また、実際問題として、ほとんど起こらないと思われる。
以下に、ICMP ソフトエラーを示す。
- ICMPv4 Destination Unreachable
- コード 0 = net unreachable
- コード 1 = host unreachable
- コード 5 = source route failed
- ICMPv6 Destination Unreachable
- コード 0 = no route to destination
- コード 3 = address unreachable
提案した方式にはあまり意味がないかもしれないが、 念のため TCP が ICMP ソフトエラーを受けた際に どう振る舞うか場合を2つに分けて説明する。
4.1) TCP の古い実装
コネクション確立前も、ソフトエラーをソフトエラーとして扱う。 TCP の再送に上限があれば、それに制約される。 BSD の場合は、10秒程度である。 上限がなければ、TCP がタイムアウトする間待たされる。
4.2) TCP の新しい実装
コネクション確立前は、ソフトエラーをハードエラーとして扱う。 すなわち、RTT の時間だけ待たされて、SMTP ポートへフォールバックする。 ユーザにはほとんど分からない。 Linux などがこの方式を採用している。
5) TCP がタイムアウトする場合
TCP タイムアウトの時間待たされて、SMTP ポートへフォールバックする。 ファイアウォールが投稿ポートへのパケットを黙って破棄する場合に起こると思われる。
各OSでの TCP タイムアウトにかかる時間は以下の通り:
| OS | TCP タイムアウトにかかる時間 |
| BSD | 75秒 |
| Linux | 189秒 |
| Solaris | 225秒 |
| Windows XP | 21秒 |
この場合においても、 (non-blocking connect() を利用し) バックグラウンドでメールを送る場合は、 ユーザにとってメールの配送が少し遅いと感じる程度であろう。 Solaris のように TCP タイムアウトが長い場合は、 メールリーダが短いタイマーを設定してもよい。
またメールリーダは、タイムアウトが起こった事実をネガティブキャッシュして、 次から同じ環境で同じサーバへメールを送信する場合は、 最初から SMTP ポートへ接続するようにしてもよい。 あるいは、タイムアウトが起こった時点で、ダイアログを表示し、 ユーザの指示を仰いでもいいだろう。
蛇足になるが、この内容は最近普及し始めている greet pause とはなんら関係ない。 greet pause は SMTP レベルの話であり、 この小節は TCP レベルの話である。 (greet pause は、サーバが accept() の後に数十秒待って write() するのだから、 クライアントの connect() は block されず、 read() が block される。)
実装とフィールド実験
すでに、Mew で バックグランドでのフォールバック機能を実装し終え、 考察通りに動作することを確認した。 また、各ケースの割合を把握するために、 フィールド実験を実施した。
実験で集まったレポートは 39 である。 その内、localhost または「自宅のサーバ」と書かれていたサーバの数が 7。 これは一般的なユーザのケースでないとして排除すると、総数は 32。 これには、ユーザとサーバの組が同じで、クライアントの位置だけ違うレポートも含まれる。 それらを吟味した結果、すべて同一のケースと見なせることが分かり、 ユーザとサーバの組で冗長性を排除すると、総数は 26 となった。
統計的に十分な調査ではないが、ある程度の傾向は分かると考えられる。
総数 26 の内、サーバの内訳は以下の通り:
| ISP | 16 |
| ASP | 1 |
| 会社 | 6 |
| 大学 | 2 |
| 不明 | 1 |
ケースの内訳は以下の通り:
| ケース1 (投稿ポート) | 12 |
| ケース2 (TCP RST) | 7 |
| ケース3 (ハードエラー) | 0 |
| ケース4 (ソフトエラー) | 0 |
| ケース5 (TCP タイムアウト) | 4 |
| SSH(22) | 2 |
| SSL(465) | 1 |
この実験を通じて得た知見:
- ケース5は、無視できない割合で存在する。 上記の実験では約15%。そのためメールリーダは、 OS の長い TCP タイムアウトを回避するために、 短いタイマーを設定すべきである。
- 投稿ポートは予想外に普及している。 上記の実験では約46%。 しかも、ユーザ認証なしで提供されている場合が多いため、 迷惑メール配送業者に悪用される可能性がある。
- メールリーダは、 サーバの返す AUTH ケーパビリティに従ってユーザ認証を実行する必要がある。 投稿ポートではユーザ認証を要求され、 フォールバック後、SMTP ポートでは要求されない場合にも、 対応できるように実装する必要がある。
- ただし、ユーザ認証に対応していないにもかかわらず、 AUTH ケーパビリティを返すサーバも存在する。 よって、ユーザ認証を無効化するオプションも必要。
- ポートレベルのフォールバックだけでなく、 IPv6 から IPv4 へのフォールバックも必要。 すなわち、 投稿ポート/IPv6 → 投稿ポート/IPv4 → SMTP ポート/IPv6 → SMTP ポート/IPv4 とフォールバックするよう実装すべきである。
結論
フォールバック技術を用いれば、 投稿ポートをデフォルトにしても、 ユーザに大きな影響を与えることはない。
バックグラウンドでメールを送信できるメールリーダの場合、 ほとんどユーザには影響を与えないだろう。
フォアグラウンドでしかメールを送信できないメールリーダの場合、 利用環境によってはフォールバックに時間がかかる。 ただし、その時間はメールリーダが短く設定可能である。 次からは SMTP ポートのみを利用する方法も考えられる。
備考
フォールバックのアイディアは、IPv6 と IPv4 のデュアルスタック環境では、 一般的である。 フォールバックに対する考察は、 長さんによる解説が詳しい。
付録A:Mew の実装方法
Emacs 21 までは、blocking connect() しか利用できなかった。 blocking connect() では、C レベルで IPv6 から IPv4 へフォールバックする。 Emacs 22 からは、non-blocking connect() も利用できる。 ただし、non-blocking connect() では、実装上の制約により IPv6 から IPv4 へのフォールバックに対応できていない。
そこで、non-blocking connect() を利用する際は、 Emacs Lisp レベルでアドレスファミリを指定し、 C レベルで利用されるアドレスファミリを明示的に限定する方法を採用した。
現時点での Mew の実装は、以下の通り。
- IPv4 を指定し投稿ポートへ non-blocking connect()
- タイマーは10秒に設定
- 上記が失敗した場合、SMTP ポートへ blocking connect()
- C レベルで IPv6 から IPv4 へフォールバック
最初に「IPv6 を指定し投稿ポートへ non-blocking connect()」を加えると対称的になるが、現状ではタイムアウトの時間が増えるだけの環境が多いので、採用していない。
上記の手続きは、TLS や SSH トンネルとも共存できるように実装してある。 SSL を利用する際は、465 ポートへ blocking connect() を用い、 SMTP ポートへはフォールバックしない。 (SMTP over SSL のためのポート番号は、正式には割り当てられていない。 465 ポートは不用意に用いられ、実質的な標準となっている。 465 ポートは、正式には Cisco のあるプロトコルに割り当てられていることに注意。)
付録B
Windows には、セキュリティソフトウェアが通信を監視する仕組みがあるので、 メールリーダの SMTP ポートへの通信を投稿ポートへ、 セキュリティソフトウェアがリレーする方法が現実的かもしれない。 この場合、セキュリティソフトウェアがフォールバックを実装する必要がある。