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
LoadDevices()

End Sub

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

Me.cmbDevices.Items.Add(x.Description)

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

Me.Close()
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
Next
End If

If loInterface IsNot Nothing Then
Me.cmdStart.Text = "Stop"
Me.DEVICE = loInterface
Me.DEVICE.Open(SharpPcap.DeviceMode.Promiscuous)
Me.DEVICE.Mode = SharpPcap.WinPcap.CaptureMode.Packets
Me.DEVICE.StartCapture()
Else
MsgBox("Select a valid interface first.", MsgBoxStyle.OkOnly, "Invalid input")
End If
Else
Try
Me.DEVICE.StopCapture()
Me.DEVICE.Close()
Catch ex As SharpPcap.PcapException
'die
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)))
Else
Exit For
End If
Next
ParseEtherNetData(loEthPacket.SourceHwAddress.ToString, loIPPacket.SourceAddress.ToString, loName.Trim)
Debug.Print(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)
Next
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
Next
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
Try

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})
Else

Me.DataGridView1.Rows.Add(lRow)
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})
Else
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?
    Thanks

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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: