Solved

vb.net network monitor

Posted on 2015-02-15
8
620 Views
Last Modified: 2015-02-20
Hi,

I am trying to build a network monitoring application using vb.net (framework 4.5).  I would like to be able to see a listing of all active connections, with their local/remote ports, IPs, and associated applications, etc...  Ideally I wouldn't have to use a timer to refresh the data, there would be some event that would fire when connections are opened or closed.

I have been researching different ways of possible accomplishing this on the web and was hoping someone could help me decide on the best approach.  And maybe provide some examples if they exists.

Option #1:  Shell out to a netstat command  
    Pros: Simple, and includes the PID
    Cons:  Not managed code, and no way to identify opening and closing connections.


Option #2:  Use the TcpConnectionInformation class
    Pros: Simple, managed code
    Cons:  No PID, and no way to identify opening and closing connections

Option #3:  Using ShappCap or pCap.NET
   Pros:  Seems like it will let me identify when new connections are opened
   Cons:  Very Complex, includes a lot more then i need.


Options 1 & 2 seem to be the simplest, but I haven't been able to find a way to identify when a connection is opened or closed.  Option 2 would be my preference, but doesn't seem to give access to the process ID.  Option #3 seems like it might let me accomplish what i am trying to do, but seems like it would introduce a lot more complexity and overhead then i need.

The main items i am missing is being able to have a event tell me when a connection is opened or closed, and getting the PID.  Are either of those possible using the TcpConnectionInformation class?

Thanks in advance..
0
Comment
Question by:MRS
  • 3
  • 2
  • 2
8 Comments
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40612026
...but I haven't been able to find a way to identify when a connection is opened or closed.
Isn't that the purpose of the "State" column in the netstat output?
0
 

Author Comment

by:MRS
ID: 40612043
Kind of, but it is always after the fact.  if I were to:

1.  run netstat
2.  then open a browser and connector to yahoo
3.  then close that browser
4.  run another netstat

I would never know about that connection.  Ideally I am looking for some kind of event that I could hook to that would notify me whenever a connection is opened or closed.
0
 
LVL 74

Expert Comment

by:käµfm³d 👽
ID: 40612120
Low-level network programming is not my forte, so I'll have to defer. Let's change up your selected topics a bit to get some wider exposure to your question.
0
Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

 
LVL 32

Expert Comment

by:it_saige
ID: 40612376
Unfortunately MRS you are correct.  The TcpConnectionInformation class does not have any events associated with the opening and/or closing of TCP connections.  My work around (as you have found) was to use a timer to regularly make a call to System.Net.NetworkInformation.GetActiveTcpConnections().  I have found that this works rather well.

As for Windows API, GetTcpTable and GetTcpTableEx, can be used to glean this information as well:

http://www.codeproject.com/Articles/4298/Getting-active-TCP-UDP-connections-on-a-box

If you need to be notified the very instant that a socket is created or when it's state changes, then you will need to look into creating a kernel mode driver (which cannot be written in .NET).

-saige-
0
 

Author Comment

by:MRS
ID: 40612422
Thanks for the response.  Are you aware of anyway of getting the Process ID from the System.Net.NetworkInformation.GetActiveTcpConnections() call?
0
 
LVL 32

Accepted Solution

by:
it_saige earned 500 total points
ID: 40612814
Unfortunately the GetActiveTcpConnections method does not give you access to the PID of the connection.  However, you can use an API call to the GetExtendedTcpTable function; e.g. -
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.Runtime.InteropServices

Module Module1
	Sub Main()
		Console.WriteLine("Active Connections")
		Console.WriteLine()
		Console.WriteLine("Proto  Local Address          Foreign Address        State         PID   Process Name")
		For Each tcpRow As TcpRow In ManagedIpHelper.GetExtendedTcpTable(True)
			Console.WriteLine(tcpRow)
		Next

		Console.Write("{0}Press any key to continue...", Environment.NewLine)
		Console.ReadKey()
	End Sub
End Module

Public Class TcpTable
	Implements IEnumerable(Of TcpRow)
	Private ReadOnly _rows As IEnumerable(Of TcpRow)

	Public Sub New(ByVal rows As IEnumerable(Of TcpRow))
		_rows = rows
	End Sub

	Public ReadOnly Property Rows() As IEnumerable(Of TcpRow)
		Get
			Return _rows
		End Get
	End Property

	Public Function GetEnumerator() As IEnumerator(Of TcpRow) Implements IEnumerable(Of EE_Q28617544.TcpRow).GetEnumerator
		Return _rows.GetEnumerator()
	End Function

	Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
		Return _rows.GetEnumerator()
	End Function
End Class

Public Class TcpRow
	Private ReadOnly _localEndPoint As IPEndPoint
	Private ReadOnly _remoteEndPoint As IPEndPoint
	Private ReadOnly _state As TcpState
	Private ReadOnly _process As Process

	Public Sub New(ByVal tcpRow As MIB_TCPROW_OWNER_PID)
		_state = tcpRow.state
		_process = Process.GetProcessById(tcpRow.owningPid)

		Dim localPort As Integer = tcpRow.LocalPort
		Dim localAddress As IPAddress = tcpRow.LocalAddress
		_localEndPoint = New IPEndPoint(localAddress, localPort)

		Dim remotePort As Integer = tcpRow.RemotePort
		Dim remoteAddress As IPAddress = tcpRow.RemoteAddress
		_remoteEndPoint = New IPEndPoint(remoteAddress, remotePort)
	End Sub

	Public ReadOnly Property LocalEndPoint() As IPEndPoint
		Get
			Return _localEndPoint
		End Get
	End Property

	Public ReadOnly Property RemoteEndPoint() As IPEndPoint
		Get
			Return _remoteEndPoint
		End Get
	End Property

	Public ReadOnly Property State() As TcpState
		Get
			Return _state
		End Get
	End Property

	Public ReadOnly Property ProcessId() As Integer
		Get
			Return _process.Id
		End Get
	End Property

	Public ReadOnly Property ProcessName() As String
		Get
			Return _process.ProcessName
		End Get
	End Property

	Public Overrides Function ToString() As String
		Return String.Format("TCP    {0,-23}{1, -23}{2,-14}{3,-6}{4}", LocalEndPoint, RemoteEndPoint, State, ProcessId, ProcessName)
	End Function
End Class

Public NotInheritable Class ManagedIpHelper
	Private Sub New()
	End Sub

	Public Shared Function GetExtendedTcpTable(ByVal sorted As Boolean) As TcpTable
		Dim tcpRows As New List(Of TcpRow)()

		Dim tcpTable As IntPtr = IntPtr.Zero
		Dim tcpTableLength As Integer = 0

		If NativeMethods.GetExtendedTcpTable(tcpTable, tcpTableLength, sorted, NativeMethods.AF_INET, NativeMethods.TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0) <> 0 Then
			Try
				tcpTable = Marshal.AllocHGlobal(tcpTableLength)
				If NativeMethods.GetExtendedTcpTable(tcpTable, tcpTableLength, True, NativeMethods.AF_INET, NativeMethods.TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0) = 0 Then
					Dim table As NativeMethods.MIB_TCPTABLE_OWNER_PID = CType(Marshal.PtrToStructure(tcpTable, GetType(NativeMethods.MIB_TCPTABLE_OWNER_PID)), NativeMethods.MIB_TCPTABLE_OWNER_PID)

					Dim rowPtr As IntPtr = New IntPtr(tcpTable.ToInt64() + Marshal.SizeOf(table.dwNumEntries))
					For i As Integer = 0 To table.dwNumEntries - 1
						tcpRows.Add(New TcpRow(CType(Marshal.PtrToStructure(rowPtr, GetType(NativeMethods.MIB_TCPROW_OWNER_PID)), NativeMethods.MIB_TCPROW_OWNER_PID)))
						rowPtr = New IntPtr(rowPtr.ToInt64() + Marshal.SizeOf(GetType(NativeMethods.MIB_TCPROW_OWNER_PID)))
					Next
				End If
			Finally
				If tcpTable <> IntPtr.Zero Then
					Marshal.FreeHGlobal(tcpTable)
				End If
			End Try
		End If
		Return New TcpTable(tcpRows)
	End Function
End Class

Public Module NativeMethods
	Public Const AF_INET As Integer = 2

	<DllImport("iphlpapi.dll", SetLastError:=True)> _
	Public Function GetExtendedTcpTable(ByVal tcpTable As IntPtr, ByRef tcpTableLength As Integer, ByVal sort As Boolean, ByVal ipVersion As Integer, ByVal tcpTableType As TCP_TABLE_CLASS, ByVal reserved As Integer) As UInteger
	End Function

	<StructLayout(LayoutKind.Sequential)> _
 Public Structure MIB_TCPROW_OWNER_PID
		' DWORD is System.UInt32 in C#
		<MarshalAs(UnmanagedType.U4)> Public state As UInt32
		<MarshalAs(UnmanagedType.U4)> Public localAddr As UInt32
		<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> Public m_localPort As Byte()
		<MarshalAs(UnmanagedType.U4)> Public remoteAddr As UInt32
		<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> Public m_remotePort As Byte()
		<MarshalAs(UnmanagedType.U4)> Public owningPid As UInt32

		Public ReadOnly Property LocalAddress() As IPAddress
			Get
				Return New IPAddress(localAddr)
			End Get
		End Property

		Public ReadOnly Property LocalPort() As UShort
			Get
				Return BitConverter.ToUInt16(New Byte(1) {m_localPort(1), m_localPort(0)}, 0)
			End Get
		End Property

		Public ReadOnly Property RemoteAddress() As IPAddress
			Get
				Return New IPAddress(remoteAddr)
			End Get
		End Property

		Public ReadOnly Property RemotePort() As UShort
			Get
				Return BitConverter.ToUInt16(New Byte(1) {m_remotePort(1), m_remotePort(0)}, 0)
			End Get
		End Property
	End Structure

	<StructLayout(LayoutKind.Sequential)> _
	Public Structure MIB_TCPTABLE_OWNER_PID
		Public dwNumEntries As UInteger
		Private table As MIB_TCPROW_OWNER_PID
	End Structure

	Public Enum TCP_TABLE_CLASS
		TCP_TABLE_BASIC_LISTENER
		TCP_TABLE_BASIC_CONNECTIONS
		TCP_TABLE_BASIC_ALL
		TCP_TABLE_OWNER_PID_LISTENER
		TCP_TABLE_OWNER_PID_CONNECTIONS
		TCP_TABLE_OWNER_PID_ALL
		TCP_TABLE_OWNER_MODULE_LISTENER
		TCP_TABLE_OWNER_MODULE_CONNECTIONS
		TCP_TABLE_OWNER_MODULE_ALL
	End Enum
End Module

Open in new window

Produces the following output -Capture.JPG-saige-
0
 

Author Closing Comment

by:MRS
ID: 40621775
thanks so much
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now