147 lines
4.9 KiB
C#
147 lines
4.9 KiB
C#
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using skyscraper5.Skyscraper.IO;
|
|
|
|
namespace skyscraper5.Ietf.Rfc971
|
|
{
|
|
public class InternetHeader
|
|
{
|
|
public InternetHeader(byte[] ipv4Header)
|
|
{
|
|
if (ipv4Header.Length < 20)
|
|
{
|
|
ChecksumValid = false;
|
|
return;
|
|
}
|
|
|
|
MemoryStream ms = new MemoryStream(ipv4Header, false);
|
|
byte readUInt8 = ms.ReadUInt8();
|
|
Version = (readUInt8 & 0xf0) >> 4;
|
|
IHL = (readUInt8 & 0x0f);
|
|
|
|
TOS = new TypeOfService(ms.ReadUInt8());
|
|
TotalLength = ms.ReadUInt16BE();
|
|
Identification = ms.ReadUInt16BE();
|
|
|
|
ushort readUInt16Be = ms.ReadUInt16BE();
|
|
DontFragment = (readUInt16Be & 0x4000) != 0;
|
|
MoreFragments = (readUInt16Be & 0x2000) != 0;
|
|
FragmentOffset = (readUInt16Be & 0x1fff);
|
|
|
|
TimeToLive = ms.ReadUInt8();
|
|
Protocol = ms.ReadUInt8();
|
|
HeaderChecksum = ms.ReadUInt16BE();
|
|
|
|
HeaderLength = IHL * 4;
|
|
|
|
SourceAddress = new IPAddress(ms.ReadBytes(4));
|
|
byte[] destAddresBytes = ms.ReadBytes(4);
|
|
int multicastTemp = destAddresBytes[0];
|
|
multicastTemp &= 0b11100000;
|
|
multicastTemp >>= 4;
|
|
if (multicastTemp == 0b1110)
|
|
IsDestinationMulticast = true;
|
|
|
|
DestinationAddress = new IPAddress(destAddresBytes);
|
|
|
|
int optionsLength = HeaderLength - (int)ms.Position;
|
|
|
|
Options = ms.ReadBytes(optionsLength);
|
|
CalculateChecksum(ipv4Header, IHL);
|
|
}
|
|
|
|
public InternetHeader(int trafficClass, int flowLabel, ushort payloadLength, byte nextHeader, byte hopLimit, IPAddress sourceAddress, IPAddress destinationAddress)
|
|
{
|
|
DestinationAddress = destinationAddress;
|
|
SourceAddress = sourceAddress;
|
|
Protocol = nextHeader;
|
|
TimeToLive = hopLimit;
|
|
TotalLength = (ushort)(payloadLength + 40);
|
|
|
|
if (DestinationAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
|
Version = 6;
|
|
else if (DestinationAddress.AddressFamily == AddressFamily.InterNetwork)
|
|
Version = 4;
|
|
else
|
|
throw new NotSupportedException(DestinationAddress.AddressFamily.ToString());
|
|
|
|
ChecksumValid = true;
|
|
}
|
|
|
|
public int HeaderLength { get; private set; }
|
|
|
|
private void CalculateChecksum(byte[] buffer, int ihl)
|
|
{
|
|
MemoryStream ms = new MemoryStream(buffer, false);
|
|
ushort checksum = ms.ReadUInt16BE(); //Version
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //Total Length
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //Identification
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //Flags
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //TTL
|
|
|
|
ms.ReadUInt16BE();
|
|
AddWithCarry(ref checksum, 0); //Checksum
|
|
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //Source IP
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //Source IP
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //Destination IP
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE()); //Destination IP
|
|
if (IHL > 5)
|
|
{
|
|
int left = IHL;
|
|
left -= 5;
|
|
for (int i = 0; i < left; i++)
|
|
{
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE());
|
|
AddWithCarry(ref checksum, ms.ReadUInt16BE());
|
|
}
|
|
}
|
|
|
|
checksum = (ushort)~checksum;
|
|
|
|
CalculatedChecksum = (ushort)checksum;
|
|
ChecksumValid = CalculatedChecksum == HeaderChecksum;
|
|
}
|
|
|
|
private void AddWithCarry(ref ushort checksum, ushort addMe)
|
|
{
|
|
ushort oldChecksum = checksum;
|
|
checksum += addMe;
|
|
if (checksum < oldChecksum)
|
|
checksum++;
|
|
}
|
|
|
|
public byte[] Options { get; private set; }
|
|
|
|
public IPAddress DestinationAddress { get; private set; }
|
|
|
|
public IPAddress SourceAddress { get; private set; }
|
|
|
|
public ushort HeaderChecksum { get; private set; }
|
|
|
|
public byte Protocol { get; private set; }
|
|
|
|
public byte TimeToLive { get; private set; }
|
|
|
|
public int FragmentOffset { get; private set; }
|
|
|
|
public bool MoreFragments { get; private set; }
|
|
|
|
public bool DontFragment { get; private set; }
|
|
|
|
public ushort Identification { get; private set; }
|
|
|
|
public ushort TotalLength { get; private set; }
|
|
|
|
public TypeOfService TOS { get; private set; }
|
|
public int IHL { get; private set; }
|
|
|
|
public int Version { get; private set; }
|
|
|
|
public bool ChecksumValid { get; private set; }
|
|
public ushort CalculatedChecksum { get; private set; }
|
|
public bool IsDestinationMulticast { get; }
|
|
}
|
|
}
|