Skip to content

Commit

Permalink
Updates and improvements to BinaryParsers and IP to use MemoryStream …
Browse files Browse the repository at this point in the history
…and BinaryReaders.
  • Loading branch information
jonmod committed Nov 19, 2015
1 parent caac49a commit ad779c3
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 123 deletions.
81 changes: 47 additions & 34 deletions Source/Tx.Network/BinaryParsers.cs
@@ -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;
Expand All @@ -25,7 +27,6 @@ public static byte ReadBits(this byte bytes, int BitPosition, int BitLength)
}
return (byte)(((0xff >> (BitPosition)) & bytes) >> bitShift);
}

public static ushort ReadNetOrderUShort(this byte[] bytes, int BufferOffset, int BitPosition, int BitLength)
{
var bitShift = 16 - BitPosition - BitLength;
Expand All @@ -35,18 +36,6 @@ public static ushort ReadNetOrderUShort(this byte[] bytes, int BufferOffset, int
}
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)
Expand All @@ -55,29 +44,53 @@ public static ushort ReadNetOrderUShort(this byte[] bytes, int BufferOffset)
}
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;
var b = bytes.ReadByte();
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
}
}
102 changes: 47 additions & 55 deletions Source/Tx.Network/IP.cs
@@ -1,4 +1,4 @@
namespace Ecs.Input.Packets
namespace Tx.Network
{
using System;
using System.Net;
Expand Down Expand Up @@ -88,13 +88,20 @@ public class IpPacket
/// <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");
Expand All @@ -107,17 +114,44 @@ public IpPacket(byte[] ReceivedDataBuffer)
{
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>
Expand Down Expand Up @@ -184,57 +218,14 @@ private void Initialize()
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
Expand Down Expand Up @@ -272,5 +263,6 @@ private void BuildPacketMemStream(byte[] DataBuffer)
PacketData = null; //sometimes the datagram is empty
}
}
#endregion
}
}
8 changes: 8 additions & 0 deletions Source/Tx.Network/Tx.Network.csproj
Expand Up @@ -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">
Expand Down
20 changes: 1 addition & 19 deletions Source/Tx.Network/UDP.cs
@@ -1,5 +1,5 @@

namespace Ecs.Input.Packets
namespace Tx.Network
{
using System;
using System.Net.Sockets;
Expand Down Expand Up @@ -47,24 +47,6 @@ public UdpDatagram(IpPacket ReceivedPacket) : base(ReceivedPacket)
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

Expand Down

0 comments on commit ad779c3

Please sign in to comment.