TCP入門


TCP (Transmission Control Protocol)

TCP はコネクション指向の、信頼性のあるバイト・ストリーム・サービスを 提供する。

「コネクション指向」とは、TCPを利用する2つのアプリケーション (一方がサーバで、他方がクライアントの場合が一般的)がデータを交換する前に、 相互にTCPコネクションを確立することである。

TCPコネクションでは、相互に通信する2箇所のエンドポイントが必ず存在する。 TCPは以下の方法で信頼性を保証する。

  1. TCPはデータを通信に最適なサイズのパケットに分割して送る。
  2. TCP はパケットを送る時にタイマーを設定し、他方のエンドから パケットが受信されたことを知らせる確認応答(Acknowlege)を待つ。 時間内に確認応答が返ってこない場合は、パケットを再転送する。
  3. TCPがパケットを受け取ると、(数秒送らせて)確認応答を送る。
  4. TCPはヘッダでチェックサムを利用する。 チェックサムが一致しない場合は、確認応答を送らない。
  5. TCPは受け取ったパケットを順番通りに並び替え、正しい順序で アプリケーションに渡す。
  6. 重複したIPデータグラムを受け取った場合は、破棄する。
  7. フロー制御を行なう。TCPコネクションの各エンドは、有限のバッファを持ち、 受信側はバッファの容量を越えない範囲でデータを受け入れる。
  8. byte stream service --- 8bitのbyte streamでデータが交換される。 TCPが(サイズなどの)情報をさしはさむことはないので、書き込み側が どのようにデータを書いたか(たとえば10byte, 20byte, 50byteに分けて書く、など) 読み出し側ではわからない(まとめて受け取られるかもしれない)。

TCP Header

    |<------------ IP Datagram ----------------->|
                  |<------- TCP Segment--------->|
    +-------------+-------------+----------------+
    | IP Header   | TCP Header  | TCP Data       |
    +-------------+-------------+----------------+
       20bytes         20bytes
                     1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 (32bits width)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Source Port              |     Destination Port          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Acknowledgement Number                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|P|R|S|F|                               |
| Offset| Reserved  |R|C|S|S|Y|I|          Window               |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Checksum             |        Urgent Pointer         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(    Options (if exists, max size=20bytes)                      )
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|             your data ...                                     |
                  ...
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

IP Address と port番号の組を、socket(ソケット)と呼ぶ。 TCPコネクションにおける2つのエンド・ポイントを socket pair (つまり、送信側のIP address とポート番号、 受信側のIP Addressとポート番号が含まれる)と呼ぶ。

TCPヘッダのオプションは、0バイト〜20バイトである。 よく使われるのが MSS (Maximum Segment Size, 最大セグメントサイズ) オプションで、コネクションの各エンドは交換する最初のパケット (SYNオプションのついたパケット)で指定する。 接続しているネットワークによって、一度に送ることのできる パケットサイズが異なるので、それを知らせるために行われる。


TCPコネクションの確立と終了

コネクションの確立

  1. クライアントは、接続したいサーバのポート番号とクライアントの初期シーケンス番号を指定したSYNパケットを送る。
  2. サーバは、サーバ側の初期シーケンス番号を含む自分自身のSYNパケットで応答する。 サーバは「クライアントの初期シーケンス番号+1」のACKを出すことで、 クライアントのSYNに確認応答する。SYNはシーケンス番号を1つ消費する。
  3. クライアントはサーバから送られてきたSYNに対して、 「サーバの初期シーケンス番号+1」のACKで確認応答を送り返さねばならない。

初期シーケンス番号は時間によって変化するため、各コネクションは異なる 初期シーケンス番号を持つ。

コネクションの終了

  1. 片方のエンドが全ての送信を終えるとき、相手にFINを送る。
  2. FINを受け取ったエンドは、他方のエンドに「FINパケットの シーケンス番号+1」のACK確認応答を送る。 また、アプリケーションに相手からの送信が終了したことを通知する(EOF)。 FINの受信は、その方向からデータが流れてこないことを意味するだけで、 自分からはまだ送信できる(ハーフ・クローズ状態)。
  3. もう片方のエンドも全ての送信を終えるとき、相手にFINを送る。
  4. FINを受け取ったエンドは、他方のエンドに 「FINパケットのシーケンス番号+1」のACK確認応答を送る。 また、アプリケーションに対して相手からの送信が終了したことを通知する(EOF)。 双方のエンドがクローズしたら通信は終了となる。


リセット・パケット

TCPヘッダのRSTは「リセット」の意味である。 一般に、ソケットペアに対して正しくないパケットが到着したとき、 リセットを送り返す。

使用されていないポート番号へのデータグラム

パスMTUディスカバリ

TCPコネクションの双方のエンドは、通信の最初にそれぞれの 接続しているネットワークのMSS (Maximum Segument Size)を TCPヘッダのオプションで伝えるのが一般的である。 しかし、経路の途中にもっと小さなMTU (Maximum Transfer Unit,一度に送ることのできる最大のバイト数) のネットワークがあると、 そのネットワークのルータがIPパケットをフラグメント化 (もっと小さな単位に分割して送る)して送る必要がある。 これはルータの性能に悪影響を与えるので、 IPパケットを最初に送り出す側が、経路の最小のMTUを調べて それ以下のサイズでIPパケットを送るのが一般的になってきた。 (ちなみに、フラグメント化されたIPパケットは途中で組み立てられることはなく、 最終的なエンドで組み立てられる)。

最小MTU値を取得するには、パスMTUディスカバリ (経路MTU探索)を使う。 パケット分割を禁止した状態のパケットが、MTUがそれより小さい経路を通ると、 ICMP (Internet Control Message Protocol) エラーメッセージが 送った側に返される。 ICMPエラーメッセージには、エラーとなった回線のMTU値とヘッダー情報が 入っているので、MTU値を調整して再送信する。 宛先に届くまでこれを繰り返せば、経路中の最小のMTU値を見つけることができる。


セキュリティの話

接続を一方向だけに許す

外部からの攻撃から内部ネットワークを守るために、 一部のパケットだけを通すフィルタリングを行うことがある。

「外部のサーバにtcp接続することはできるが、外部から内部のサーバには 接続できない」ようにするには、 外部から内部へ送られるTCP接続開始パケット (SYNフラグがONで、ACKフラグがOFFになっている) をルータで捨てればよい。

IP Spoofing

外部からのアクセスにはセキュリティを厳格に適用するが、 内部からのアクセスにはセキュリティを甘く設定する例がよくある。 そのような状況を利用して侵入するために、 外部からIPヘッダのSource Addressを内部のIPアドレスに 偽装してIPパケットを送りつけることがある。

その際にTCPコネクションを確立するには、TCPシーケンス番号予測攻撃などを 併用する。

外部からのIPパケットなのにSource Addressが内部ネットワークの アドレスになっている場合は、そのパケットを捨てるなどの対策が必要となる。

DoS攻撃

DoS攻撃(Denial of Service Attack)とは、 攻撃対象のサービス提供を妨害することを目的として 大量のIPパケットを送りつけてくる攻撃である。