Updates and improvements to BinaryParsers and IP to use MemoryStream and BinaryReaders.

This commit is contained in:
jonmod 2015-11-16 13:55:34 -08:00
Родитель caac49af67
Коммит ad779c32b7
6 изменённых файлов: 193 добавлений и 123 удалений

Просмотреть файл

@ -1,21 +1,23 @@
namespace Ecs.Input.Packets
namespace Tx.Network
{
using System;
using System.Net;
using System.IO;
public static class BinaryParsers
/// <summary>
/// Extentions to Byte[] to:
/// - read bits at specified offsets from either a Byte or a network order UShort
/// - read a single Byte or network order UShort
/// - read an IPv4 Address
/// </summary>
public static class ByteArrayExtentions
{
#region Byte[] Extentions
public static byte ReadBits(this byte[] bytes, int BufferOffset, int BitPosition, int BitLength)
{
return bytes[BufferOffset].ReadBits(BitPosition, BitLength);
}
public static byte ReadBits(this BinaryReader bytes, int BitPosition, int BitLength, bool Advance = false)
{
if(Advance) return bytes.ReadByte().ReadBits(BitPosition, BitLength);
return bytes.PeekByte().ReadBits(BitPosition, BitLength);
}
public static byte ReadBits(this byte bytes, int BitPosition, int BitLength)
{
var bitShift = 8 - BitPosition - BitLength;
@ -25,7 +27,6 @@
}
return (byte)(((0xff >> (BitPosition)) & bytes) >> bitShift);
}
public static ushort ReadNetOrderUShort(this byte[] bytes, int BufferOffset, int BitPosition, int BitLength)
{
var bitShift = 16 - BitPosition - BitLength;
@ -35,18 +36,6 @@
}
return (ushort)IPAddress.NetworkToHostOrder(((0xffff >> BitPosition) & BitConverter.ToUInt16(bytes, BufferOffset) >> bitShift));
}
public static ushort ReadNetOrderUShort(this BinaryReader bytes, int BitPosition, int BitLength)
{
var bitShift = 16 - BitPosition - BitLength;
if (bitShift < 0)
{
throw new Exception("BitPostion + BitLength greater than 16 for ushort output type.");
}
return (ushort)IPAddress.NetworkToHostOrder(((0xffff >> BitPosition) ) & bytes.ReadUInt16() >> bitShift);
}
public static ushort ReadNetOrderUShort(this byte[] bytes, int BufferOffset)
{
if (bytes.Length - BufferOffset < 2)
@ -55,22 +44,24 @@
}
return (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(bytes, BufferOffset));
}
public static ushort ReadNetOrderUShort(this BinaryReader bytes)
{
return (ushort)IPAddress.NetworkToHostOrder(bytes.ReadInt16());
}
public static IPAddress ReadIpAddress(this byte[] bytes, int Offset)
public static IPAddress ReadIpAddress(this byte[] bytes, int BufferOffset)
{
var IpBytes = new byte[4];
Array.Copy(bytes, Offset, IpBytes, 0, 4);
Array.Copy(bytes, BufferOffset, IpBytes, 0, 4);
return new IPAddress(IpBytes);
}
public static IPAddress ReadIpAddress(this BinaryReader bytes)
{
return new IPAddress(bytes.ReadBytes(4));
}
#endregion
}
/// <summary>
/// Extentions to BinaryReader to:
/// - read bits at specified offsets from either a Byte or a network order UShort
/// - read a single Byte or network order UShort
/// - read an IPv4 Address
/// - look at the current byte without moving the the position in the stream
/// </summary>
public static class BinaryReaderExtentions
{
#region BinaryReader Extentions
public static byte PeekByte(this BinaryReader bytes)
{
var pos = bytes.BaseStream.Position;
@ -78,6 +69,28 @@
bytes.BaseStream.Seek(pos, 0);
return b;
}
public static byte ReadBits(this BinaryReader bytes, int BitPosition, int BitLength, bool Advance = false)
{
if (Advance) return bytes.ReadByte().ReadBits(BitPosition, BitLength);
return bytes.PeekByte().ReadBits(BitPosition, BitLength);
}
public static ushort ReadNetOrderUShort(this BinaryReader bytes)
{
return (ushort)IPAddress.NetworkToHostOrder(bytes.ReadInt16());
}
public static ushort ReadNetOrderUShort(this BinaryReader bytes, int BitPosition, int BitLength)
{
var bitShift = 16 - BitPosition - BitLength;
if (bitShift < 0)
{
throw new Exception("BitPostion + BitLength greater than 16 for ushort output type.");
}
return (ushort)IPAddress.NetworkToHostOrder(((0xffff >> BitPosition)) & bytes.ReadUInt16() >> bitShift);
}
public static IPAddress ReadIpAddress(this BinaryReader bytes)
{
return new IPAddress(bytes.ReadBytes(4));
}
#endregion
}
}

Просмотреть файл

@ -1,4 +1,4 @@
namespace Ecs.Input.Packets
namespace Tx.Network
{
using System;
using System.Net;
@ -88,13 +88,20 @@
/// <exception cref="ArgumentOutOfRangeException">Thrown on empty or null input byte[].</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown on input byte[] too small -- minimum 20-bytes.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown on input byte[] too large -- maximum 65,535-bytes.</exception>
public IpPacket(byte[] ReceivedDataBuffer)
public IpPacket(byte[] ReceivedDataBuffer) : this(new MemoryStream(ReceivedDataBuffer)) { }
/// <summary>
/// Produces a IpPacket based on input
/// </summary>
/// <param name="ReceivedDataBuffer">Incoming packet in a MemoryStream without alterations or prior processing </param>
/// <returns> A new IpPacket. </returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown on empty or null input byte[].</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown on input byte[] too small -- minimum 20-bytes.</exception>
/// <exception cref="ArgumentOutOfRangeException">Thrown on input byte[] too large -- maximum 65,535-bytes.</exception>
public IpPacket(MemoryStream ReceivedDataBuffer)
{
Initialize();
DataBuffer = new byte[ReceivedDataBuffer.Length];
Array.Copy(ReceivedDataBuffer, DataBuffer, ReceivedDataBuffer.Length);
if (DataBuffer.Length == 0 || DataBuffer == null || Array.TrueForAll(DataBuffer, j => j == 0))
{
throw new ArgumentOutOfRangeException("ReceivedDataBuffer", "Input byte[] is empty or null");
@ -107,17 +114,44 @@
{
throw new ArgumentOutOfRangeException("ReceivedDataBuffer", "Input byte[] is larger than the maximum IP packet size of 65,535-bytes");
}
BuildPacketMemStream(DataBuffer);
BuildPacket(DataBuffer);
}
/// <summary>
/// Produces a IpPacket based on input
/// </summary>
/// <param name="ReceivedPacket">IpPacket to copy to a new instance</param>
public IpPacket(IpPacket ReceivedPacket) : this(ReceivedPacket.DataBuffer) { }
/// <remarks> This method copies all data from the ReceivedPacket into a new packet, including byte arrays.</remarks>
public IpPacket(IpPacket ReceivedPacket)
{
Initialize();
IpVersion = ReceivedPacket.IpVersion;
InternetHeaderLength = ReceivedPacket.InternetHeaderLength;
DscpValue = ReceivedPacket.DscpValue;
ExplicitCongestionNotice = ReceivedPacket.ExplicitCongestionNotice;
IpPacketLength = ReceivedPacket.IpPacketLength;
FragmentGroupId = ReceivedPacket.FragmentGroupId;
IpHeaderFlags = ReceivedPacket.IpHeaderFlags;
FragmentOffset = ReceivedPacket.FragmentOffset;
TimeToLive = ReceivedPacket.TimeToLive;
ProtocolNumber = ReceivedPacket.ProtocolNumber;
Protocol = ReceivedPacket.Protocol;
PacketHeaderChecksum = ReceivedPacket.PacketHeaderChecksum;
SourceIpAddress = new IPAddress(ReceivedPacket.SourceIpAddress.GetAddressBytes());
DestinationIpAddress = new IPAddress(ReceivedPacket.DestinationIpAddress.GetAddressBytes());
IpOptions = new byte[ReceivedPacket.IpOptions.Length];
PacketData = new byte[ReceivedPacket.PacketData.Length];
DataBuffer = new byte[ReceivedPacket.DataBuffer.Length];
Array.Copy(ReceivedPacket.IpOptions, IpOptions, ReceivedPacket.IpOptions.Length);
Array.Copy(ReceivedPacket.PacketData, PacketData, ReceivedPacket.PacketData.Length);
Array.Copy(ReceivedPacket.DataBuffer, DataBuffer, ReceivedPacket.DataBuffer.Length);
}
#endregion
#region Public Methods
/// <summary>
/// Creates a string representation of the IpPacket object.
/// </summary>
@ -184,57 +218,14 @@
PacketData = null;
DataBuffer = null;
}
private void BuildPacket(byte[] DataBuffer)
{
var ipVers = DataBuffer[0].ReadBits(0, 4); //bits 0 to 3
//ensure this is v4
if (ipVers != 4)
{
throw new Exception("IPv4 only currently supported");
}
InternetHeaderLength = DataBuffer[0].ReadBits(4, 4); //bits 4 to 7
DscpValue = DataBuffer[1].ReadBits(0, 6); //8 to 13
ExplicitCongestionNotice = DataBuffer[1].ReadBits(6, 2); //14 to 15
IpPacketLength = DataBuffer.ReadNetOrderUShort(2); //16 to 31
FragmentGroupId = DataBuffer.ReadNetOrderUShort(4); //32 to 47
IpHeaderFlags = DataBuffer[6].ReadBits(0, 3); //48 to 50
FragmentOffset = DataBuffer.ReadNetOrderUShort(6, 3, 13); //51 to 63
TimeToLive = DataBuffer[8]; //64 to 71
ProtocolNumber = DataBuffer[9]; //72 to 79
Protocol = (ProtocolType)ProtocolNumber; //Enum
PacketHeaderChecksum = BitConverter.ToUInt16(DataBuffer, 10); //80 to 95
SourceIpAddress = DataBuffer.ReadIpAddress(12); //96 to 127
DestinationIpAddress = DataBuffer.ReadIpAddress(16); //128 to 160
if (InternetHeaderLength > 5) //161 and up
{
IpOptions = new byte[(InternetHeaderLength - 5) * 4];
Array.Copy(DataBuffer, 20, IpOptions, 0, (InternetHeaderLength - 5) * 4);
}
else
{
IpOptions = null;
}
//IpHeader in bytes is 4*IHL bytes long
if (IpPacketLength > 4 * InternetHeaderLength)
{
PacketData = new byte[IpPacketLength - (InternetHeaderLength * 4)];
Array.Copy(DataBuffer, InternetHeaderLength * 4, PacketData, 0, IpPacketLength - InternetHeaderLength * 4);
}
else
{
PacketData = null; //sometimes the datagram is empty
}
BuildPacket(new MemoryStream(DataBuffer));
}
#endregion
private void BuildPacketMemStream(byte[] DataBuffer)
private void BuildPacket(MemoryStream Stream)
{
var packetBytes = new BinaryReader(new MemoryStream(DataBuffer));
var packetBytes = new BinaryReader(Stream);
var ipVers = packetBytes.ReadBits(0, 4); //bits 0 to 3
if (ipVers != 4) throw new Exception("IPv4 only currently supported"); //ensure this is v4
@ -272,5 +263,6 @@
PacketData = null; //sometimes the datagram is empty
}
}
#endregion
}
}

Просмотреть файл

@ -28,14 +28,22 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Reactive.Linq, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\References\DESKTOPCLR40\System.Reactive.Linq.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\AssemblyInfo.cs">
<Link>Properties\AssemblyInfo.cs</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Compile>
<Compile Include="BinaryParsers.cs" />
<Compile Include="IP.cs" />
<Compile Include="Pcap.cs" />
<Compile Include="PcapNg.cs" />
<Compile Include="UDP.cs" />
<Compile Include="UDPReceiver.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\key.snk">

Просмотреть файл

@ -1,5 +1,5 @@

namespace Ecs.Input.Packets
namespace Tx.Network
{
using System;
using System.Net.Sockets;
@ -47,24 +47,6 @@ namespace Ecs.Input.Packets
UdpCheckSum = PacketData.ReadNetOrderUShort(6);
}
}
public UdpDatagram(IpPacket ReceivedPacket, bool HeaderOnly = false) : this()
{
if (Protocol == ProtocolType.Udp) IsUdp = true;
if (!HeaderOnly)
{
UdpData = new byte[PacketData.Length - 8];
Array.Copy(PacketData, 8, UdpData, 0, PacketData.Length - 8);
}
if (IsUdp && PacketData.Length > 8)
{
SourcePort = PacketData.ReadNetOrderUShort(0);
DestinationPort = PacketData.ReadNetOrderUShort(2);
UdpLength = PacketData.ReadNetOrderUShort(4);
UdpCheckSum = PacketData.ReadNetOrderUShort(6);
}
}
#endregion

Просмотреть файл

@ -1,4 +1,4 @@
namespace Ecs.Input.Packets
namespace Tx.Network
{
using System;
using System.Collections.Concurrent;
@ -6,7 +6,7 @@
using System.Net.Sockets;
using System.Reactive.Subjects;
public class Receiver : IObservable<IpPacket>, IDisposable
public class UdpReceiver : IObservable<IpPacket>, IDisposable
{
#region Public Fields
public IPEndPoint ListenEndPoint { get; private set; }
@ -16,10 +16,9 @@
#endregion
#region Private Fields
private Subject<IpPacket> _packetSubject { get; set; }
private ConcurrentQueue<SocketAsyncEventArgs> _receivedDataProcessorsPool { get; set; }
bool subscribed;
Subject<IpPacket> _packetSubject { get; set; }
ConcurrentQueue<SocketAsyncEventArgs> _receivedDataProcessorsPool { get; set; }
bool _subscribed { get; set; }
#endregion
#region Constructors
@ -32,7 +31,7 @@
/// <remarks>Concurrent receivers allow for scaling of allocated buffers.
/// each receiver holds up to 64k bytes and multiple receivers allow for concurrent packet
/// reception from the underlying socket object.</remarks>
public Receiver(IPAddress ListenAddress, int ListenPort = 514, uint ConcurrentReceivers = 10)
public UdpReceiver(IPAddress ListenAddress, int ListenPort = 514, uint ConcurrentReceivers = 10)
: this(new IPEndPoint(ListenAddress, ListenPort), ConcurrentReceivers)
{ }
@ -45,7 +44,7 @@
/// <remarks>Concurrent receivers allow for scaling of allocated buffers.
/// each receiver holds up to 64k bytes and multiple receivers allow for concurrent packet
/// reception from the underlying socket object.</remarks>
public Receiver(string ListenAddress, int ListenPort = 514, uint ConcurrentReceivers = 10)
public UdpReceiver(string ListenAddress, int ListenPort = 514, uint ConcurrentReceivers = 10)
: this(new IPEndPoint(IPAddress.Parse(ListenAddress), ListenPort), ConcurrentReceivers)
{ }
@ -57,7 +56,7 @@
/// <remarks>Concurrent receivers allow for scaling of allocated buffers.
/// each receiver holds up to 64k bytes and multiple receivers allow for concurrent packet
/// reception from the underlying socket object.</remarks>
public Receiver(IPEndPoint ListenEndPoint, uint ConcurrentReceivers = 10)
public UdpReceiver(IPEndPoint ListenEndPoint, uint ConcurrentReceivers = 10)
{
ListenProtocol = ProtocolType.Udp;
this.ConcurrentReceivers = ConcurrentReceivers;
@ -75,9 +74,9 @@
public IDisposable Subscribe(IObserver<IpPacket> observer)
{
var o = _packetSubject.Subscribe(observer);
if (!subscribed)
if (!_subscribed)
{
subscribed = true;
_subscribed = true;
Start();
}
return o;
@ -85,9 +84,6 @@
#endregion
#region Private Methods
/// <summary>
/// Starts the receiver.
/// </summary>
private void Start()
{
_receivedDataProcessorsPool = new ConcurrentQueue<SocketAsyncEventArgs>();
@ -105,12 +101,13 @@
Socket.Bind(ListenEndPoint);
GetDataProcessorAndReceive();
}
private void ReceiveCompletedHandler(object caller, SocketAsyncEventArgs socketArgs)
{
if (!disposeCalled)
{
GetDataProcessorAndReceive(); //call a new processor
//var packet = new IP(socketArgs.Buffer);
//var packet = new IP(socketArgs.Buffer);
var packet = new IpPacket();
var packetCheck = IsDestinationListenEndpoint(socketArgs.Buffer, out packet);

78
Tools/UdpSyslogPlayer.ps1 Normal file
Просмотреть файл

@ -0,0 +1,78 @@

param(
[string] $IP = "127.0.0.1",
[int] $Port = 514,
[string] $SampleFile = ".\syslogsample.csv",
[int] $SleepTimer = 1000
)
$i = import-csv $SampleFile
[System.Net.Sockets.UdpClient] $u = New-Object -TypeName System.Net.Sockets.UdpClient
$Address = [System.Net.IPAddress]::Parse($IP)
$fac = @{ kernel = 0;
userlevel = 1;
mailsystem = 2;
systemdaemons = 3;
authorization = 4;
syslog = 5;
printer = 6;
news = 7;
uucp = 8;
clock = 9;
securityauth = 10;
ftp = 11;
ntp = 12;
logaudit = 13;
logalert = 14;
clockdaemon = 15;
local0 = 16;
local1 = 17;
local2 = 18;
local3 = 19;
local4 = 20;
local5 = 21;
local6 = 22;
local7 = 23;
}
$sev = @{emergency = 0;
alert = 1;
critical = 2;
error = 3;
warning = 4;
notice = 5;
informaitonal = 6;
debug = 7;
}
#$i[0].Context
#$i[0].Severity
#$i[0].Message
#$i[0].Hostname
#$i[0].Facility
#$i[0].IPAddress
foreach ($j in $i){
#Pri is the same as 8*(Facility) + Severity
[int] $f = if($fac[$j.Facility.ToLower()] -ne $null){ [int]$fac[$j.Facility.ToLower()] }else{ 17 }
[int] $s = [int]$sev[$j.Severity.tolower()]
[int] $pri = ($f * 8) + $s
[string] $d = [DateTime]$j.Time | get-date -Format "MMM dd hh:mm:ss"
[string] $o = "<" + $pri.ToString() + "> " + $d + " " + $j.hostname + " " + $j.message
#for($x = 1; $x -lt 20; $o += $j.message){}
$b = [byte[]]$o.ToCharArray()
$o
$u.Send($b, $b.Length,$Address,$Port)
sleep -Milliseconds $SleepTimer
}