SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

仮想ネットワークの実装で学ぶTCP/IP

仮想ネットワーク実装でTCP/IPを学ぼう(4)
― トランスポート層の勘所

仮想ネットワーク実装でTCP/IPを学ぼう(4)


  • X ポスト
  • このエントリーをはてなブックマークに追加

コネクションの確立

 コネクションの確立はクライアントがその旨をサーバーに伝えるためのTCPセグメントを送ることから始まります。

 この段階をアクティブ・オープンと呼びます。

アクティブ・オープンの模倣(C#)
//TcpClientクラスから抜粋
/// <summary>
/// TCPのコネクションを確立します。
/// </summary>
/// <param name="data">送信するデータ</param>
/// <param name="portNumber">指定するポート番号</param>
/// <param name="sequenceNumber">シーケンス番号</param>
/// <param name="nic">使用するデバイスドライバ</param>
protected void Connect ( Frame data, ushort portNumber, ref uint sequenceNumber, Nic nic )
{
    //接続が確立されるまで繰り返し処理をする。
    while ( this.state != TcpConnectionState.Open ) {
        switch ( this.state ) {
            case TcpConnectionState.Nothing:
                sequenceNumber = 0;
                TcpSegment segment = new TcpSegment ( );
                segment.Syn = true;
                segment.SequenceNumber = sequenceNumber;
                segment.SourcePortNumber = portNumber;
                segment.DestinationPortNumber = portNumber;
                data.Data.UserData = segment;
                nic.Send ( data );
                break;
        }
    }

    //関係のないコードは省略しています
}
アクティブ・オープンの模倣(VB.NET)
'TcpClientクラスから抜粋
''' <summary>
''' TCPのコネクションを確立します。
''' </summary>
''' <param name="data">送信するデータ</param>
''' <param name="portNumber">指定するポート番号</param>
''' <param name="sequenceNumber">シーケンス番号</param>
''' <param name="nic">使用するデバイスドライバ</param>
Protected Sub Connect(ByVal data As Frame, ByVal portNumber As UShort, ByRef sequenceNumber As UInteger, ByVal nic As Nic)
    '接続が確立されるまで繰り返し処理をする。
    While (Me.state <> TcpConnectionState.Open)
        Select Case Me.state
            Case TcpConnectionState.Null
                sequenceNumber = 0
                Dim segment As TcpSegment = New TcpSegment()
                segment.Syn = True
                segment.SequenceNumber = sequenceNumber
                segment.SourcePortNumber = portNumber
                segment.DestinationPortNumber = portNumber
                data.Data.UserData = segment
                nic.Send(data)
        End Select
    End While

    '関係のないコードは省略しています
End Sub

 クライアントはポート番号(指定するアプリケーション層)と初期のシーケンス番号を指定し、SYNフラグを立てたTCPセグメントをサーバーへ宛に送信します。今回は分かりやすくするために初期シーケンス番号を0にしていますが、初期シーケンス番号が0もしくは推測されやすい値ですと、他者が信頼されているクライアントになりすますことが可能となってしまいますので、実際はランダムな値が指定されます。Kevin Mitnick氏が下村務氏のシステムに仕掛けたリモート攻撃は、この仕組みを利用したものだと言われています。

 クライアントからこのセグメントを受け取ったサーバーは、適切なセグメントをクライアントに送り返します。

 この段階のことをパッシブ・オープンと呼びます。

パッシブ・オープンの模倣(C#)
//TcpServerクラスから抜粋
/// <summary>
/// クラアントとのやり取りを行います。
/// </summary>
/// <param name="data">受信したデータ</param>
/// <param name="nic">使用するドライバ</param>
public void Receive ( Frame data, Nic nic )
{
    //現在の接続状態に基づいて適切な処理をする
    SocketPair info = GetConnectionInfo ( packet.SourceAddress, segment.SourcePortNumber );
    if ( info == null ) {
        #region 初めてなので情報を登録する
        SocketPair pair = new SocketPair ( );
        pair.ServerIPAddress = this.IP;
        pair.ServerPortNumber = segment.DestinationPortNumber;
        pair.ClientIPAddress = packet.SourceAddress;
        pair.ClientPortNumber = segment.SourcePortNumber;
        pair.State = TcpConnectionState.ActiveOpen;
        this.connections.Add ( pair );
        #endregion
        #region 返答をする

        //TCPセグメント
        TcpSegment resultSegment = new TcpSegment ( );
        resultSegment.SourcePortNumber = segment.DestinationPortNumber;
        resultSegment.DestinationPortNumber = segment.SourcePortNumber;
        resultSegment.Syn = true; //ここに注目
        resultSegment.Ack = true; //ここに注目
        resultSegment.SequenceNumber = segment.SequenceNumber;
        resultSegment.AcknowledgementNumber = segment.SequenceNumber + 1; //ここに注目

        //IPパケットとMACフレームを作成する部分のコードを省略しました

        //返答を送信
        nic.Send ( ( Frame ) resultMac );
        #endregion
        return;
    }
    //関係のないコードは省略しています
}
パッシブ・オープンの模倣(VB.NET)
'TcpServerクラスから抜粋
''' <summary>
''' クラアントとのやり取りを行います。
''' </summary>
''' <param name="data">受信したデータ</param>
''' <param name="nic">使用するドライバ</param>
Public Sub Receive(ByVal data As Frame, ByVal nic As Nic)
    '現在の接続状態に基づいて適切な処理をする
    Dim info As SocketPair = GetConnectionInfo(packet.SourceAddress, segment.SourcePortNumber)
    If info Is Nothing Then
        '初めてなので情報を登録する"
        Dim pair As SocketPair = New SocketPair()
        pair.ServerIPAddress = Me.IP
        pair.ServerPortNumber = segment.DestinationPortNumber
        pair.ClientIPAddress = packet.SourceAddress
        pair.ClientPortNumber = segment.SourcePortNumber
        pair.State = TcpConnectionState.ActiveOpen
        Me.connections.Add(pair)
        '--------------------返答をする--------------------

        'TCPセグメント
        Dim resultSegment As TcpSegment = New TcpSegment()
        resultSegment.SourcePortNumber = segment.DestinationPortNumber
        resultSegment.DestinationPortNumber = segment.SourcePortNumber
        resultSegment.Syn = True 'ここに注目
        resultSegment.Ack = True 'ここに注目
        resultSegment.SequenceNumber = segment.SequenceNumber
        resultSegment.AcknowledgementNumber = CUInt(segment.SequenceNumber + 1) 'ここに注目

        'IPパケットとMACフレームを作成する部分のコードを省略しました

        '返答を送信
        nic.Send(CType(resultMac, Frame))
        Return
    End If
    '関係のないコードは省略しています
End Sub

 サーバーが送るセグメントは、SYNフラグとACKフラグをONにして、確認応答番号に初期シーケンス番号+1の値を設定したものです。

 このセグメントを受け取ったクライアントは、そのポート番号を使用しているサービスが使用できることと、サーバーが稼動していることを知ることができます。

 最後にクライアントはサーバーからの返答を受信したことを知らせるためにセグメントを送ります。

(C#)
//TcpClientクラスから抜粋
/// <summary>
/// TCPのコネクションを確立します。
/// </summary>
/// <param name="data">送信するデータ</param>
/// <param name="portNumber">指定するポート番号</param>
/// <param name="sequenceNumber">シーケンス番号</param>
/// <param name="nic">使用するデバイスドライバ</param>
protected void Connect ( Frame data, ushort portNumber, ref uint sequenceNumber, Nic nic )
{
    //接続が確立されるまで繰り返し処理をする。
    while ( this.state != TcpConnectionState.Open ) {
        switch ( this.state ) {
            case TcpConnectionState.PassiveOpen:
                segment = new TcpSegment ( );
                segment.Ack = true; //ここがポイント
                segment.SequenceNumber = this.nextNumber;
                segment.AcknowledgementNumber = this.nextNumber;
                segment.SourcePortNumber = portNumber;
                segment.DestinationPortNumber = portNumber;
                data.Data.UserData = segment;
                nic.Send ( data );
                this.state = TcpConnectionState.Open;
                break;
        }
    }
    //関係のないコードは省略しています
}
(VB.NET)
'TcpClientクラスから抜粋
''' <summary>
''' TCPのコネクションを確立します。
''' </summary>
''' <param name="data">送信するデータ</param>
''' <param name="portNumber">指定するポート番号</param>
''' <param name="sequenceNumber">シーケンス番号</param>
''' <param name="nic">使用するデバイスドライバ</param>
Protected Sub Connect(ByVal data As Frame, ByVal portNumber As UShort, ByRef sequenceNumber As UInteger, ByVal nic As Nic)
    '接続が確立されるまで繰り返し処理をする。
    While (Me.state <> TcpConnectionState.Open)
        Select Case Me.state
            Case TcpConnectionState.PassiveOpen
                Dim segment As TcpSegment = New TcpSegment()
                segment.Ack = True 'ここに注目
                segment.SequenceNumber = Me.nextNumber
                segment.AcknowledgementNumber = Me.nextNumber
                segment.SourcePortNumber = portNumber
                segment.DestinationPortNumber = portNumber
                data.Data.UserData = segment
                nic.Send(data)
                Me.state = TcpConnectionState.Open
        End Select
    End While

    '関係のないコードは省略しています
End Sub

 以上の3つのセグメントをやり取りすることによりコネクションの確立は完了します。この手順をスリーウェイ・ハンドシェイクと呼びます。

 次項ではコネクションの終了について解説します。

次のページ
コネクションの終了

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
仮想ネットワークの実装で学ぶTCP/IP連載記事一覧

もっと読む

この記事の著者

インドリ(インドリ)

分析・設計・実装なんでもありのフリーエンジニア。ブログ「無差別に技術をついばむ鳥(http://indori.blog32.fc2.com/)」の作者です。アドバイザーをしたり、システム開発したり、情報処理技術を研究したりと色々しています。座右の銘は温故知新で、新旧関係なく必要だと考えたものは全て学...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4209 2010/04/27 12:07

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング