What we are going to do is, to try and retrieve every tcp connection, its state, its local and remote adresses and ports, and it's owning process. We could also use GetTcpTable to for the same job, but i noticed that it is only available in Vista, so we'll go with GetExtendedTcpTable for now, as it is working on both Vista and Xp Sp2.
Let's start with coding, here is a detailed module about what we need, so create a new module and paste this :
Imports System.Runtime.InteropServices Imports System.Net.NetworkInformation Imports System.Net Public Module TCPGet 'Api to get table Declare Auto Function GetExtendedTcpTable Lib "iphlpapi.dll" (ByVal pTCPTable As IntPtr, ByRef OutLen As Integer, ByVal Sort As Boolean, ByVal IpVersion As Integer, ByVal dwClass As Integer, ByVal Reserved As Integer) As Integer 'const : we are asking for connections with ProcessIDs', all of them. Const TCP_TABLE_OWNER_PID_ALL As Integer = 5 'represents a full table <StructLayout(LayoutKind.Sequential)> _ Public Structure MIB_TCPTABLE_OWNER_PID Public NumberOfEntries As Integer 'number of rows Public Table As IntPtr 'array of tables End Structure 'represents a row <StructLayout(LayoutKind.Sequential)> _ Public Structure MIB_TCPROW_OWNER_PID Public state As Integer 'state of the connection Public localAddress As UInteger Public LocalPort As Integer Public RemoteAddress As UInteger Public remotePort As Integer Public PID As Integer 'Process ID End Structure 'this a structure that we made to store a connection after formatting it Structure TcpConnection Public State As TcpState Public localAddress As String Public LocalPort As Integer Public RemoteAddress As String Public remotePort As Integer Public Proc As String End Structure 'Main Function Function GetAllTCPConnections() As MIB_TCPROW_OWNER_PID() GetAllTCPConnections = Nothing 'we need to know how much memory we need to store all the connections Dim cb As Integer 'so we call GetExtendedTcpTable without a pointer to a table to get the size GetExtendedTcpTable(Nothing, cb, False, 2, TCP_TABLE_OWNER_PID_ALL, 0) 'after getting the size, we allocate memory Dim tcptable As IntPtr = Marshal.AllocHGlobal(cb) 'the call where we store the connections in that memory If GetExtendedTcpTable(tcptable, cb, False, 2, TCP_TABLE_OWNER_PID_ALL, 0) = 0 Then 'we convert it to a MIB_TCPTABLE_OWNER_PID variable Dim tab As MIB_TCPTABLE_OWNER_PID = Marshal.PtrToStructure(tcptable, GetType(MIB_TCPTABLE_OWNER_PID)) 'and we make an array with a size of number of connections Dim Mibs(tab.NumberOfEntries - 1) As MIB_TCPROW_OWNER_PID 'row represents the adress of a MIB_TCPROW in memory Dim row As IntPtr 'for each connection For i As Integer = 0 To tab.NumberOfEntries - 1 'adress = adress of table + 4(int32) + (size of a MIB_TCPROW * i) row = New IntPtr(tcptable.ToInt32 + Marshal.SizeOf(tab.NumberOfEntries) + Marshal.SizeOf(GetType(MIB_TCPROW_OWNER_PID)) * i) 'convert pointer to a MIB_TCPROW, and store it in the array Mibs(i) = Marshal.PtrToStructure(row, GetType(MIB_TCPROW_OWNER_PID)) Next 'returning the array GetAllTCPConnections = Mibs End If 'just before leaving, clean up your memory! Marshal.FreeHGlobal(tcptable) End Function 'MIB_TCPROW_OWNER_PID is not well formatted, we need to format it. Function MIB_ROW_To_TCP(ByVal row As MIB_TCPROW_OWNER_PID) As TcpConnection Dim tcp As New TcpConnection tcp.State = DirectCast(row.state, TcpState) 'a State enum is better than an int 'IP adresses are stored in long format, we can simply convert it this way Dim ipad As New IPAddress(row.localAddress) tcp.localAddress = ipad.ToString 'also the port is in network byte order,we need to convert it as well tcp.LocalPort = row.LocalPort / 256 + (row.LocalPort Mod 256) * 256 'another ip ipad = New IPAddress(row.RemoteAddress) tcp.RemoteAddress = ipad.ToString 'another port tcp.remotePort = row.remotePort / 256 + (row.remotePort Mod 256) * 256 'for the process, all we get is the ID. Let's get also the name. Dim p As Process = Process.GetProcessById(row.PID) tcp.Proc = p.ProcessName & " (" & row.PID.ToString & ")" 'just freeing this variable since we don't need it anymore. p.Dispose() 'done. Return tcp End Function End Module
Let's Create a Listview as the following to display connections :
Now let's call our function and add each connection to this listview :
'Clear Items ListView1.Items.Clear() 'For Each MIB_TCPROW For Each Row In GetAllTCPConnections() 'We Convert It Dim Tcp As TcpConnection = MIB_ROW_To_TCP(Row) 'Add SubItems to a ListViewItem Dim l As New ListViewItem(New String() {Tcp.State.ToString, Tcp.localAddress, Tcp.LocalPort, Tcp.RemoteAddress, Tcp.remotePort, Tcp.Proc}) 'Add The Item ListView1.Items.Add(l) Next
That's about it, we can now see all tcp connections thanks to this great API.
As for UDP Connections, we can use the GetExtendedUdpTable Function with MIB_UDPTABLE_OWNER_PID and MIB_UDPROW_OWNER_PID Structures with a very similar piece of code to list them in an array, and show them in a listview if you like so.
2 comments:
Hi, this is very helpful.
Thank you very much.
Hi, any chance to example of GetExtendedudpTable?
Thanks
Post a Comment