124 lines
4.6 KiB
C#
124 lines
4.6 KiB
C#
using System;
|
|
namespace ln.types.net
|
|
{
|
|
public class IPv4Header
|
|
{
|
|
public byte Version { get; set; }
|
|
public byte IHL { get; set; }
|
|
public byte TypeOfService { get; set; }
|
|
|
|
public ushort TotalLength { get; set; }
|
|
public ushort Identification { get; set; }
|
|
|
|
public byte Flags { get; set; }
|
|
public ushort FragmentOffset { get; set; }
|
|
|
|
public byte TimeToLive { get; set; }
|
|
public byte Protocol { get; set; }
|
|
public ushort HeaderChecksum { get; set; }
|
|
|
|
public IPv4 SourceAddress { get; set; }
|
|
public IPv4 DestinationAddress { get; set; }
|
|
|
|
public byte[] Options { get; set; }
|
|
|
|
public IPv4Header()
|
|
{
|
|
}
|
|
|
|
public int HeaderLength => IHL << 2;
|
|
public void Write(byte[] buffer, int offset) => Write(buffer, offset, false);
|
|
public void Write(byte[] buffer,int offset,bool performChecksum)
|
|
{
|
|
if (buffer.Length < HeaderLength)
|
|
throw new ArgumentOutOfRangeException(nameof(buffer));
|
|
if (offset + HeaderLength < buffer.Length)
|
|
throw new ArgumentOutOfRangeException(nameof(offset));
|
|
|
|
if ((Options.Length % 4) != 0)
|
|
throw new InvalidOperationException("IPv4Header.Options must be length multiple of 4");
|
|
|
|
if ((Options.Length + 20) != HeaderLength)
|
|
throw new InvalidOperationException("IHL must match .Header and .Options length");
|
|
|
|
if (performChecksum)
|
|
HeaderChecksum = 0;
|
|
|
|
int i = (Version) | (IHL << 4) | (TypeOfService << 8) | (TotalLength << 16);
|
|
Array.Copy(BitConverter.GetBytes(i), 0, buffer, offset, 4);
|
|
i = (Identification) | (Flags << 16) | (FragmentOffset << 19);
|
|
Array.Copy(BitConverter.GetBytes(i), 0, buffer, offset + 4, 4);
|
|
i = (TimeToLive) | (Protocol << 8) | (HeaderChecksum << 16);
|
|
Array.Copy(BitConverter.GetBytes(i), 0, buffer, offset + 8, 4);
|
|
|
|
Array.Copy(SourceAddress.IPBytes, 0, buffer, offset + 12, 4);
|
|
Array.Copy(SourceAddress.IPBytes, 0, buffer, offset + 16, 4);
|
|
|
|
Array.Copy(Options, 0, buffer, offset + 20, Options.Length);
|
|
|
|
if (performChecksum)
|
|
{
|
|
HeaderChecksum = PerformChecksum(buffer,offset,HeaderLength);
|
|
Array.Copy(BitConverter.GetBytes(HeaderChecksum), 0, buffer, offset + 10, 4);
|
|
}
|
|
}
|
|
|
|
public byte[] ToBytes() => ToBytes(false);
|
|
public byte[] ToBytes(bool performChecksum)
|
|
{
|
|
byte[] packet = new byte[HeaderLength];
|
|
Write(packet, 0, performChecksum);
|
|
return packet;
|
|
}
|
|
public static ushort PerformChecksum(byte[] headerBytes) => PerformChecksum(headerBytes, 0, headerBytes.Length);
|
|
public static ushort PerformChecksum(byte[] headerBytes,int offset,int length)
|
|
{
|
|
uint chksum = 0;
|
|
|
|
for (int n = 0; n < headerBytes.Length; n += 4)
|
|
chksum += BitConverter.ToUInt16(headerBytes, n);
|
|
|
|
chksum += (chksum & 0xFFFF) + (chksum >> 16);
|
|
if ((chksum & 0xFFFF0000)!=0)
|
|
chksum += (chksum & 0xFFFF) + (chksum >> 16);
|
|
|
|
return (ushort)((~chksum) & 0xFFFF);
|
|
}
|
|
|
|
public static IPv4Header Parse(byte[] packet,int offset,int length)
|
|
{
|
|
if (offset >= packet.Length)
|
|
throw new ArgumentOutOfRangeException(nameof(offset));
|
|
if ((offset + length > packet.Length)|| (length < 20))
|
|
throw new ArgumentOutOfRangeException(nameof(length));
|
|
|
|
IPv4Header header = new IPv4Header();
|
|
|
|
uint ui = BitConverter.ToUInt32(packet, offset);
|
|
|
|
header.Version = (byte)(ui & 0x0F);
|
|
header.IHL = (byte)((ui & 0xF0) >> 4);
|
|
header.TypeOfService = (byte)(ui >> 8);
|
|
header.TotalLength = (ushort)(ui >> 16);
|
|
|
|
ui = BitConverter.ToUInt32(packet, offset + 4);
|
|
header.Identification = (ushort)(ui & 0x0000FFFF);
|
|
header.Flags = (byte)((ui & 0x00070000) >> 16);
|
|
header.FragmentOffset = (ushort)((ui & 0xFFF80000) >> 19);
|
|
|
|
ui = BitConverter.ToUInt32(packet, offset + 4);
|
|
header.TimeToLive = (byte)(ui & 0x000000FF);
|
|
header.Protocol = (byte)((ui & 0x0000FF00) >> 8);
|
|
header.HeaderChecksum = (ushort)((ui & 0xFFFF0000)>>16);
|
|
|
|
header.SourceAddress = new IPv4(packet, 12);
|
|
header.DestinationAddress= new IPv4(packet, 16);
|
|
|
|
header.Options = packet.Slice(20,header.HeaderLength - 20);
|
|
|
|
return header;
|
|
}
|
|
|
|
}
|
|
}
|