2025-07-22 22:08:21 +02:00

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; }
}
}