RFCで定義されているTCPの仕様に問題があり、悪意のある第3者がTCPのセッションを勝手に切ってしまうことが出来る可能性が、これまで考えられていたものよりずっと上がったという話らしいです。よく出来たまとめがセキュリティホールmemoなどにあるので、詳しい内容についてはそちらを見てもらうとして、FreeBSD 4.8-RELEASE-p17のソースの該当部分を見てみました。
問題のファイルは/usr/src/sys/netinet/tcp_input.cで、1335行目から始まるコメントの、
* If the RST bit is set, check the sequence number to see * if this is a valid reset segment. * RFC 793 page 37: * In all states except SYN-SENT, all reset (RST) segments * are validated by checking their SEQ-fields. A reset is * valid if its sequence number is in the window.
という部分は今回の問題を6行でうまくまとめてあります(^^;。実際のチェック処理はコメントのすぐ後ろにあり、次のようになっています。
if (thflags & TH_RST) { if (SEQ_GEQ(th->th_seq, tp->last_ack_sent) && SEQ_LT(th->th_seq, tp->last_ack_sent + tp->rcv_wnd)) { 以下、クローズ処理
TCPヘッダのRSTフラグが立っていて、かつ受け取ったパケットのシーケンス番号が最後に送信したACKパケットのシーケンス番号以上で、シーケンス番号+ウィンドウサイズ以下なら、コネクションを閉じる。という実装のようです。このソースを読むまでは、RSTのシーケンス番号は「ふつー」上のソースで言うlast_ack_sentと同じ値であることを期待して
if (thflags & TH_RST) { if (SEQ_EQ(th->th_seq, tp->last_ack_sent)) { (←実際にはSEQ_EQ()というマクロはありません。/usr/include/netinet/tcp_seq.hを参照) 以下、クローズ処理
と書き直せば良いんじゃないの?とか思ってたのですが、コメントの1359行目以降に、それが出来ない理由が書いてあります。
* The sequence number in the reset segment is normally an * echo of our outgoing acknowlegement numbers, but some hosts * send a reset with the sequence number at the rightmost edge * of our receive window, and we have to handle this case. * If we have multiple segments in flight, the intial reset * segment sequence numbers will be to the left of last_ack_sent, * but they will eventually catch up. * In any case, it never made sense to trim reset segments to * fit the receive window since RFC 1122 says: * 4.2.2.12 RST Segment: RFC-793 Section 3.4 * * A TCP SHOULD allow a received RST segment to include data. * * DISCUSSION * It has been suggested that a RST segment could contain * ASCII text that encoded and explained the cause of the * RST. No standard has yet been established for such * data.
うーん。読めば読むほど実によくまとまっています。このコメントを書いた人は実は気づいてたんじゃなかろうかと思ったり思わなかったり。
GWにやろうと思っていた自転車のタイヤ交換を、やんごとなき理由で前倒し。タイヤ自体は1時間ほどで前後ともに交換できたのですが、ブレーキの調整からグリスの塗り直しとエスカレートしてしまい、結局1日作業に。
[clear] 左は交換前のタイヤ、1年ぐらい前にパンクで交換したものですが、重りを仕込んでるんじゃないかと思うぐらい前に進まなかったので、今回はB003A6UXGWというタイヤにしてみました。
作業自体は古いタイヤを外し、リムテープを張り直し、チューブをあらかじめタイヤに入れておいて、進行方向を確認した上でタイヤをつけるだけなので、1本20分もかかりませんでした。
中央はブレーキもばらしてグリスを塗っているところ。ブレーキが左右比対称に開くのを、はじめバネを手で曲げて調整していて、ここまできたらついでにグリスも塗ろうとばらしたところで調整用のねじの存在に気付いたり。
右は今回買ったシュワルベというメーカのタイヤチューブのバルブですが、虫ゴムじゃない!!
スーパーバルブと言うそうです。
さてこれで明日からの通勤が楽になる、かな?