Making a passive network scanner in .NEt (PacketDotNet)

Came across the Packet.NEt the other day, a great interface to capture and dissect network packets in .Net
To test it I made a little passive network scanner that listens for incoming packets and registers ip addresses, hardware addresses and netbios addresses. Must say that I’m quite pleased with this library.

The code below is the code-behind for a form named form1. I marked the form controls red so you can quickly see what you need to add to your form to make this work

Imports SharpPcap
Imports PacketDotNet

Public Class Form1
Public DEVICE_LIST As SharpPcap.WinPcap.WinPcapDeviceList
Public WithEvents DEVICE As SharpPcap.WinPcap.WinPcapDevice

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

End Sub

Private Sub LoadDevices()
'laod devices
DEVICE_LIST = SharpPcap.WinPcap.WinPcapDeviceList.[New]
For Each x As SharpPcap.WinPcap.WinPcapDevice In DEVICE_LIST


Catch ex As Exception
MsgBox("Failed to load Device lsit, exiting", MsgBoxStyle.OkOnly)

End Try

End Sub

Private Sub cmdStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdStart.Click

If Me.cmdStart.Text = "Start" Then
Dim loInterface As SharpPcap.WinPcap.WinPcapDevice = Nothing

If Me.cmbDevices.SelectedIndex >= 0 Then
For Each x As SharpPcap.WinPcap.WinPcapDevice In DEVICE_LIST
If x.Description = Me.cmbDevices.Items(Me.cmbDevices.SelectedIndex).ToString Then
loInterface = x
Exit For
End If
End If

If loInterface IsNot Nothing Then
Me.cmdStart.Text = "Stop"
Me.DEVICE = loInterface
Me.DEVICE.Mode = SharpPcap.WinPcap.CaptureMode.Packets
MsgBox("Select a valid interface first.", MsgBoxStyle.OkOnly, "Invalid input")
End If
Catch ex As SharpPcap.PcapException
End Try

Me.cmdStart.Text = "Start"
End If

End Sub

Private Sub DEVICE_OnPacketArrival(ByVal sender As Object, ByVal e As SharpPcap.CaptureEventArgs) Handles DEVICE.OnPacketArrival

Dim loPacket As PacketDotNet.Packet = PacketDotNet.Packet.ParsePacket(PacketDotNet.LinkLayers.Ethernet, e.Packet.Data)

Dim loIPPacket As PacketDotNet.IpPacket
Dim loEthPacket As PacketDotNet.EthernetPacket

Dim lsIp As String = ""
Dim lsHWAddr As String

loEthPacket = PacketDotNet.EthernetPacket.ParsePacket(LinkLayers.Ethernet, e.Packet.Data)

If loEthPacket.PayloadPacket IsNot Nothing Then
Select Case loEthPacket.PayloadPacket.GetType.ToString

Case "PacketDotNet.ARPPacket"
Dim loArpPacket As PacketDotNet.ARPPacket
loArpPacket = PacketDotNet.ARPPacket.GetEncapsulated(loPacket)
If loArpPacket IsNot Nothing Then ParseEtherNetData(loArpPacket.SenderHardwareAddress.ToString, loArpPacket.SenderProtocolAddress.ToString)
'If loArpPacket IsNot Nothing Then ParseEtherNetData(loArpPacket.TargetHardwareAddress.ToString, loArpPacket.TargetProtocolAddress.ToString)
'skip this, mostly broadcast
Case "PacketDotNet.IPv4Packet"  '"PacketDotNet.TcpPacket"
loIPPacket = loEthPacket.PayloadPacket
If loIPPacket IsNot Nothing Then
If loIPPacket.SourceAddress.AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork Then
ParseEtherNetData(loEthPacket.SourceHwAddress.ToString, loIPPacket.SourceAddress.ToString)
ParseEtherNetData(loEthPacket.DestinationHwAddress.ToString, loIPPacket.DestinationAddress.ToString)
End If

If loIPPacket.PayloadPacket IsNot Nothing Then
If loIPPacket.PayloadPacket.GetType.ToString = "PacketDotNet.UdpPacket" Then
Dim loUDPPacket As PacketDotNet.UdpPacket = loIPPacket.PayloadPacket
Select Case loUDPPacket.SourcePort
Case 53 'dns

Case 138 'netbios datagram
Debug.Print(loUDPPacket.Length & ":" & loUDPPacket.PayloadData.Length)
If loUDPPacket.DestinationPort = 138 Then 'host announcment?
Debug.Print(loUDPPacket.Length & ":" & loUDPPacket.PayloadData.Length)
If loUDPPacket.PayloadData.Length = 201 And CInt(loUDPPacket.PayloadData(0).ToString) = 17 And CInt(loUDPPacket.PayloadData(168).ToString) = 1 Then 'Direct group datagram: host anouncement
Dim loName As String
For i As Integer = 0 To 15
If loUDPPacket.PayloadData(174 + i) <> 0 Then
loName = loName & Chr(CInt(loUDPPacket.PayloadData(174 + i)))
Exit For
End If
ParseEtherNetData(loEthPacket.SourceHwAddress.ToString, loIPPacket.SourceAddress.ToString, loName.Trim)

End If
End If

End Select
End If
End If

End If
Case Else

Debug.Print("### " & loEthPacket.PayloadPacket.GetType.ToString)
End Select
End If

End Sub

Private Sub ParseEtherNetData(ByVal HWaddress As String, Optional ByVal lsip As String = "", Optional ByVal HostName As String = "")
Dim lbExists As Boolean = False
Dim lsMac As String = ""
If HWaddress <> "" Then
For i As Integer = 1 To Len(HWaddress) Step 2
If lsMac <> "" Then lsMac = lsMac & ":"
lsMac = lsMac & Mid(HWaddress, i, 2)
End If

If lsip <> "" Then
For Each xrow As DataGridViewRow In Me.DataGridView1.Rows
If xrow.Cells("IP4Addr").Value = lsip Then
lbExists = True
If lsMac <> "" Then UpdateCell(xrow.Cells("MACAddr"), lsMac)
If HostName <> "" Then UpdateCell(xrow.Cells("Hostname"), HostName)
UpdateCell(xrow.Cells("PacketCount"), CInt(xrow.Cells("PacketCount").Value) + 1)

Exit For
End If
End If

If lbExists = False Then CreateRow(lsip, lsMac, HostName)

End Sub

Delegate Sub CreatRowCallback(ByVal lsip As String, ByVal lsMAc As String, ByVal lsHOst As String)
Private Sub CreateRow(Optional ByVal lsip As String = "", Optional ByVal lsMAc As String = "", Optional ByVal lsHOst As String = "")
If lsMAc = "00:00:00:00:00:00" Or lsMAc = "FF:FF:FF:FF:FF:FF" Then Exit Sub

Dim lRow As New DataGridViewRow
Dim loCellSeen As DataGridViewCell = New DataGridViewTextBoxCell : loCellSeen.Value = Now
Dim loCellIP As DataGridViewCell = New DataGridViewTextBoxCell : loCellIP.Value = lsip
Dim loCellMac As DataGridViewCell = New DataGridViewTextBoxCell : loCellMac.Value = lsMAc
Dim loCellHost As DataGridViewCell = New DataGridViewTextBoxCell : loCellHost.Value = lsHOst
Dim loCellCount As DataGridViewCell = New DataGridViewTextBoxCell : loCellCount.Value = 1

lRow.Cells.Add(loCellSeen) lRow.Cells.Add(loCellIP) lRow.Cells.Add(loCellMac) lRow.Cells.Add(loCellHost) lRow.Cells.Add(loCellCount)
If Me.DataGridView1.InvokeRequired Then
Dim x As New CreatRowCallback(AddressOf CreateRow)
Me.DataGridView1.Invoke(x, {lsip, lsMAc, lsHOst})

If Me.DataGridView1.SortedColumn IsNot Nothing Then Me.DataGridView1.Sort(Me.DataGridView1.SortedColumn, Me.DataGridView1.SortOrder - 1) 'yes, -1 dumb,asses

End If
Catch ex As Exception
'unload event: die
Debug.Print(ex.Message & vbCrLf & ex.StackTrace)
End Try

End Sub

Delegate Sub UpdateCellCallback(ByVal loCel As DataGridViewCell, ByVal lsVal As String)
Private Sub UpdateCell(ByVal loCel As DataGridViewCell, ByVal lsVal As String)
If Me.DataGridView1.InvokeRequired = True Then
Dim x As New UpdateCellCallback(AddressOf UpdateCell)
Me.DataGridView1.Invoke(x, {loCel, lsVal})
Me.DataGridView1.Rows(loCel.RowIndex).Cells(loCel.ColumnIndex).Value = lsVal
Me.DataGridView1.Rows(loCel.RowIndex).Cells("Seen").Value = Now

If Me.DataGridView1.SortedColumn IsNot Nothing Then Me.DataGridView1.Sort(Me.DataGridView1.SortedColumn, Me.DataGridView1.SortOrder - 1)
End If
End Sub

End Class

One Response to Making a passive network scanner in .NEt (PacketDotNet)

  1. I like your code for the PacketDotNet example. How would you modify it get LLDP information?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: