Skip to content

Commit

Permalink
Merge pull request #9 from cocowalla/feat/library
Browse files Browse the repository at this point in the history
feat: split out functionality into a library (fixes #8)
  • Loading branch information
cocowalla authored Sep 14, 2020
2 parents 1e29a06 + eb3f463 commit 9859b30
Show file tree
Hide file tree
Showing 59 changed files with 2,271 additions and 649 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,6 @@ $RECYCLE.BIN/

# Windows shortcuts
*.lnk

# Rider
.idea/
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Snifter
=======

[![NuGet](https://img.shields.io/nuget/v/Snifter.svg)](https://www.nuget.org/packages/Snifter)

<table border="0">
<tr>
<td>
Expand All @@ -14,8 +16,8 @@ Snifter
</pre>
</td>
<td>
<p>Snifter is a raw socket IP packet capturing tool for Windows and Linux, with a tiny CPU and memory footprint.</p>
<p>Output is written in <a href="https://github.com/pcapng/pcapng">PCAPNG</a> format, and you can filter captured packets based on protocol, source/destination address and source/destination port.</p>
<p>Snifter is a raw socket IP packet capturing library/app for Windows and Linux, with a tiny CPU and memory footprint.</p>
<p>Output can be written to <a href="https://github.com/pcapng/pcapng">PCAPNG</a> files, and you can filter captured packets based on protocol, source/destination address and source/destination port.</p>
</td>
</tr>
</table>
Expand All @@ -25,14 +27,24 @@ Why?

On Windows, you can't capture on the local loopback address `127.0.0.1` with a packet capture driver like [WinPcap](https://wiki.wireshark.org/WinPcap) - but you can by using a *raw socket* sniffer, like Snifter.

Additionally, Snifter is a cross-platform, portable tool that doesn't require any drivers to be installed.
Additionally, Snifter is a cross-platform, portable library/tool that doesn't require any drivers to be installed.

Snifter started life only for Windows, and Linux support was later added thanks to .NET Core.

Getting Started
---------------
Install the [Snifter](https://www.nuget.org/packages/Snifter) package from NuGet:

```powershell
Install-Package Snifter
```

Snifter started life as a Windows-only tool, and Linux support was later added just because .NET Core makes it possible.
You can see an example of how to use the library in the `Snifter.App` code in `src/App`, including capturing, parsing, filtering and saving packets.

Limitations
-----------
App Limitations
---------------

You must run Snifter with elevated privileges on Windows, or with `sudo` on Linux - this is an OS-level requirement to create raw sockets.
You must run `Snifter.App` with elevated privileges on Windows, or with `sudo` on Linux - this is an OS-level requirement to create raw sockets.

For now at least, Snifter only supports IPv4. It should be straightforward to add support for IPv6, but I don't use IPv6 yet, so haven't added it.

Expand Down
8 changes: 7 additions & 1 deletion Snifter.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Snifter", "src\Snifter.csproj", "{BD011029-7C87-495C-A135-BDA549DB03CF}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Snifter", "src\Snifter\Snifter.csproj", "{BD011029-7C87-495C-A135-BDA549DB03CF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{E76A7FDE-F7FA-49BC-AC9C-1B1ADEDBC35A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -15,6 +17,10 @@ Global
{BD011029-7C87-495C-A135-BDA549DB03CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD011029-7C87-495C-A135-BDA549DB03CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD011029-7C87-495C-A135-BDA549DB03CF}.Release|Any CPU.Build.0 = Release|Any CPU
{E76A7FDE-F7FA-49BC-AC9C-1B1ADEDBC35A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E76A7FDE-F7FA-49BC-AC9C-1B1ADEDBC35A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E76A7FDE-F7FA-49BC-AC9C-1B1ADEDBC35A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E76A7FDE-F7FA-49BC-AC9C-1B1ADEDBC35A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
5 changes: 4 additions & 1 deletion Snifter.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,7 @@
<s:String x:Key="/Default/Environment/PerformanceGuide/SwitchBehaviour/=VCS/@EntryIndexedValue">LIVE_MONITOR</s:String>
<s:String x:Key="/Default/Environment/PerformanceGuide/SwitchBehaviour/=VsBulb/@EntryIndexedValue">DO_NOTHING</s:String>
<s:String x:Key="/Default/Environment/PerformanceGuide/SwitchBehaviour/=XAML_0020Designer/@EntryIndexedValue">LIVE_MONITOR</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=IANA/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCAPNG/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unpadded/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
6 changes: 5 additions & 1 deletion build.cmd
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
dotnet restore .\Snifter.sln
dotnet build .\src\Snifter.csproj --configuration Release --framework net471

dotnet build .\src\App\App.csproj --configuration Release
dotnet build .\src\Snifter\Snifter.csproj --configuration Release

dotnet pack .\src\Snifter -c Release
3 changes: 2 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
set -ev

dotnet restore ./Snifter.sln
dotnet build ./src/Snifter.csproj --configuration Release --framework netcoreapp2.1
dotnet build ./src/App/App.csproj --configuration Release --framework netcoreapp3.1
dotnet build ./src/Snifter/Snifter.csproj --configuration Release --framework netcoreapp3.1
37 changes: 37 additions & 0 deletions src/App/App.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net471;netcoreapp3.1</TargetFrameworks>

<AssemblyName>Snifter.App</AssemblyName>
<RootNamespace>Snifter.App</RootNamespace>
<Description>Raw Socket Sniffer</Description>
<VersionPrefix>1.3.0</VersionPrefix>
<LangVersion>latest</LangVersion>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<Authors>Colin Anderson</Authors>
<Copyright>Copyright © Colin Anderson 2020</Copyright>
<RepositoryUrl>http://github.com/cocowalla/snifter</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Security.Principal.Windows" Version="4.5.1" />

<!--Unfortunately, Mono.Posix.NETStandard forwards to Mono.Posix when compiling for net471, which doesn't necessarily exist on windows-->
<PackageReference Include="Mono.Posix" Version="5.4.0.201" Condition="'$(OS)' == 'Windows_NT'" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" Condition="$(OS) != 'Windows_NT'" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Snifter\Snifter.csproj" />
</ItemGroup>

</Project>
18 changes: 10 additions & 8 deletions src/AppOptions.cs → src/App/AppOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using System.IO;
using System.Net;
using Snifter.Filter;
using Snifter.Protocol.Internet;
using Snifter.Protocol.Transport;

namespace Snifter
namespace Snifter.App
{
public class AppOptions
{
Expand Down Expand Up @@ -50,33 +52,33 @@ public void Parse(string[] args)
this.optionSet.Parse(args);
}

public Filters<IPPacket> BuildFilters()
public Filters<IIpPacket> BuildFilters()
{
var filters = new Filters<IPPacket>(this.FilterOperator);
var filters = new Filters<IIpPacket>(this.FilterOperator);

if (this.FilterProtocol.HasValue)
{
filters.PropertyFilters.Add(new PropertyFilter<IPPacket>(x => x.Protocol, this.FilterProtocol.Value));
filters.PropertyFilters.Add(new PropertyFilter<IIpPacket>(x => x.Protocol, this.FilterProtocol.Value));
}

if (this.FilterSourceAddress != null)
{
filters.PropertyFilters.Add(new PropertyFilter<IPPacket>(x => x.SourceAddress, this.FilterSourceAddress));
filters.PropertyFilters.Add(new PropertyFilter<IIpPacket>(x => x.SourceAddress, this.FilterSourceAddress));
}

if (this.FilterDestAddress != null)
{
filters.PropertyFilters.Add(new PropertyFilter<IPPacket>(x => x.DestAddress, this.FilterDestAddress));
filters.PropertyFilters.Add(new PropertyFilter<IIpPacket>(x => x.DestinationAddress, this.FilterDestAddress));
}

if (this.FilterSourcePort.HasValue)
{
filters.PropertyFilters.Add(new PropertyFilter<IPPacket>(x => x.SourcePort, this.FilterSourcePort.Value));
filters.PropertyFilters.Add(new PropertyFilter<IIpPacket>(x => x.TransportPacket is IHasPorts hasPorts ? (ushort?)hasPorts.SourcePort : null, this.FilterSourcePort.Value));
}

if (this.FilterDestPort.HasValue)
{
filters.PropertyFilters.Add(new PropertyFilter<IPPacket>(x => x.DestPort, this.FilterDestPort.Value));
filters.PropertyFilters.Add(new PropertyFilter<IIpPacket>(x => x.TransportPacket is IHasPorts hasPorts ? (ushort?)hasPorts.DestinationPort : null, this.FilterDestPort.Value));
}

return filters;
Expand Down
2 changes: 1 addition & 1 deletion src/Options.cs → src/App/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
using System.Text;
using System.Text.RegularExpressions;

namespace Snifter
namespace Snifter.App
{
public class OptionValueCollection : IList, IList<string>
{
Expand Down
31 changes: 17 additions & 14 deletions src/Program.cs → src/App/Program.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
using System;
using System.Security.Principal;
using System.Threading;
using Snifter.Outputs.PcapNg;
using Snifter.Output.PcapNg;

namespace Snifter
namespace Snifter.App
{
internal class Program
internal static class Program
{
private static bool isStopping;

private static void Main(string[] args)
{
// You can only create raw sockets with elevated privileges
if (!SystemInformation.IsAdmin())
if (!UserInformation.IsAdmin())
{
var message = SystemInformation.IsWindows
? "Please run with elevated prilileges"
Expand Down Expand Up @@ -42,33 +41,37 @@ private static void Main(string[] args)
}

var filters = appOptions.BuildFilters();
var nic = nics[appOptions.InterfaceId.Value];
var nic = nics[appOptions.InterfaceId!.Value];

// Start capturing packets
var output = new PcapNgFileOutput(nic, appOptions.Filename);
var sniffer = new SocketSniffer(nic, filters, output);
sniffer.Start();

// Shutdown gracefully on CTRL+C
Console.CancelKeyPress += ConsoleOnCancelKeyPress;

Console.WriteLine();
Console.WriteLine("Capturing on interface {0} ({1})", nic.Name, nic.IPAddress);
Console.WriteLine("Saving to file {0}", appOptions.Filename);
Console.WriteLine("Press CTRL+C to stop");
Console.WriteLine();
Console.WriteLine();
Console.WriteLine();

// Shutdown gracefully on CTRL+C
Console.CancelKeyPress += ConsoleOnCancelKeyPress;

Console.WriteLine();
Console.WriteLine();

while (!isStopping)
{
Console.SetCursorPosition(0, Console.CursorTop - 2);
Console.WriteLine("Packets Observed: {0}", sniffer.PacketsObserved);
Console.WriteLine("Packets Captured: {0}", sniffer.PacketsCaptured);
Console.SetCursorPosition(0, Console.CursorTop - 4);
Console.WriteLine("Packets Observed: {0} ", sniffer.Statistics.PacketsObserved);
Console.WriteLine("Packets Captured: {0} ", sniffer.Statistics.PacketsCaptured);
Console.WriteLine("Packets Dropped: {0} ", sniffer.Statistics.PacketsDropped);
Console.WriteLine("Buffers in Use: {0} ", sniffer.Statistics.BuffersInUse);

Thread.Sleep(200);
}

sniffer.Stop();
}

Expand Down
19 changes: 19 additions & 0 deletions src/App/UserInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Security.Principal;
using Mono.Unix.Native;

namespace Snifter.App
{
public static class UserInformation
{
public static bool IsAdmin()
{
if (SystemInformation.IsWindows)
{
return new WindowsPrincipal(WindowsIdentity.GetCurrent())
.IsInRole(WindowsBuiltInRole.Administrator);
}

return Syscall.geteuid() == 0;
}
}
}
31 changes: 0 additions & 31 deletions src/BufferManager.cs

This file was deleted.

50 changes: 0 additions & 50 deletions src/IPPacket.cs

This file was deleted.

Loading

0 comments on commit 9859b30

Please sign in to comment.