Future Convergence PRJ.

主にプログラミング関連で調べたことのメモ(趣味プログラムなので動作は保証しません)

VB.NETでパケットキャプチャ作成

VB.NETでパケットキャプチャー作成のメモ。
参考にしたサイトのURL:http://sekki.org/wordpress/?p=212

ソースはこんな感じ。

Imports System.Net
Imports System.Net.Sockets
Imports System.Text

Module PacTest

    Sub Main()

        '文字コードはUTF8にする
        Dim enc As Encoding = Encoding.UTF8
        '自分のIPアドレスを設定する
        Dim ip As String = "192.168.3.100"
        'パケットのカウント
        Dim packetCounter As Integer = 0

        Dim socket As New Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP)
        socket.Bind(New IPEndPoint(IPAddress.Parse(ip), 0))
        socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AcceptConnection, True)
        socket.IOControl(IOControlCode.ReceiveAll, New Byte() {1, 0, 0, 0}, New Byte() {0, 0, 0, 0})

        Using ws As New System.IO.StreamWriter("C:\test\packet.txt", False, enc)

            Do
                Dim buff As Byte() = New Byte(4095) {}

                socket.Receive(buff)

                'IPパケットヘッダ情報の取得
                'パケットサイズ
                Dim packetSize As Integer = buff(2) * 256 + buff(3)
                'プロトコル番号
                Dim protocolNum As Integer = buff(9)
                '送信元IP
                Dim srcIP As String = String.Format("{0}.{1}.{2}.{3}", buff(12), buff(13), buff(14), buff(15))
                '送信先IP
                Dim dstIP As String = String.Format("{0}.{1}.{2}.{3}", buff(16), buff(17), buff(18), buff(19))
                '(ここから先はIPヘッダではない)
                '送信元Port
                Dim srcPort As Integer = buff(20) * 256 + buff(21)
                '送信先Port
                Dim dstPort As Integer = buff(22) * 256 + buff(23)

                'パケットをUTF8での文字列で取得
                Dim utf8Str As String = enc.GetString(buff, 0, packetSize)

                'コンソールにパケットカウント数と送信元IP/ポート、送信先IP/ポートを表示
                'コンソールにUTF8での文字列を表示させようとすると、エラーになるので表示させない
                '理由:IPヘッダ部分とうはUTF8で文字にできないので化け文字になる→化け文字はコンソール表示不可で落ちる
                Console.WriteLine("packetCount={0}", packetCounter)
                Console.WriteLine("送信元{0}/{1}  -  送信先{2}/{3}", srcIP, srcPort, dstIP, dstPort)
                Console.WriteLine()

                'ファイルへの書き出し(ファイルは化け文字があっても問題がない)
                ws.WriteLine("[PacketCount={0}]", packetCounter.ToString.PadLeft(6, "0"))
                ws.WriteLine("送信元{0}/{1}  -  送信先{2}/{3}", srcIP, srcPort, dstIP, dstPort)
                ws.WriteLine("packetSize={0}, protocolNum={1}", packetSize, protocolNum)
                ws.WriteLine(utf8Str)
                ws.WriteLine()

                ws.Write("----------------------- BINARY -----------------------")

                'パケットの内容を16進数で表記
                For i As Integer = 0 To packetSize - 1

                    If (i Mod 16) = 0 Then
                        ws.WriteLine()
                        ws.Write("{0}:", (i / 16).ToString().PadLeft(4, "0"))
                    End If

                    ws.Write(" {0}", Convert.ToString(buff(i), 16).PadLeft(2, "0"))

                Next
                ws.WriteLine()
                ws.WriteLine("------------------------------------------------------")
                ws.WriteLine()
                ws.WriteLine()

                packetCounter = packetCounter + 1

            Loop
        End Using

    End Sub

End Module


以下注意点
Windows7(たぶんWindows Vista以降)ではセキュリティが強化されてる関係で、管理者権限で実行する必要がある。管理者権限でないと以下のソースの部分で「アクセス許可で禁じられた方法でソケットにアクセスしようとしました。」と例外が発生して落ちる。なので、デバッグでの実行はできない。リリースビルドして出来たexeファイルを管理者権限で実行する。

Dim socket As New Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP)


また、動かしてみると送信パケットしかキャプチャされていないことに気が付く。調べてみると、Windowsファイアウォールが受信パケットを遮断しているらしい(これもWindows Vista以降?)。
コントロールパネルのWindowsファイアウォールから詳細設定を選択し、受信規則で新しい規則を作成、すべてのプログラムを接続許可できるように設定することで、受信パケットもキャプチャできるようになる。