Next add the ICMP for Ipv6 header definition class.
class Icmpv6Header : ProtocolHeader { private byte icmpType; private byte icmpCode; private ushort icmpChecksum;
public Ipv6Header ipv6Header;
// Common values for the ICMPv6 type and code fields static public byte Icmpv6EchoRequestType = 128; // ICMPv6 echo request type static public byte Icmpv6EchoRequestCode = 0; // ICMPv6 echo request code static public byte Icmpv6EchoReplyType = 129; // ICMPv6 echo reply type static public byte Icmpv6EchoReplyCode = 0; // ICMPv6 echo reply code static public int Icmpv6HeaderLength = 4; // ICMPv6 header length
/// <summary> /// Simple constructor for the ICMPv6 protocol header. /// </summary> public Icmpv6Header() : base() { icmpType = 0; icmpCode = 0; icmpChecksum = 0; }
/// <summary> /// Constructor for the ICMPv6 header which also takes a reference to the /// encompassing IPv6 header. This is necessary since the IPv6 protocol /// defines a pseudo header checksum which requires the checksum to be /// calculated over fields in the ICMPv6 header and payload as well as /// fields from the IPv6 packet. /// </summary> /// <param name="packetHeader">Reference to the Ipv6Header object encompassing the ICMPv6 packet</param> public Icmpv6Header(Ipv6Header packetHeader) : base() { icmpType = 0; icmpCode = 0; icmpChecksum = 0; ipv6Header = packetHeader; }
/// <summary> /// Sets the ICMPv6 message type. /// </summary> public byte Type { get { return icmpType; } set { icmpType = value; } }
/// <summary> /// Sets the ICMPv6 code type. /// </summary> public byte Code { get { return icmpCode; } set { icmpCode = value; } }
/// <summary> /// The ICMPv6 checksum value. This value is computed over the ICMPv6 header, payload, /// and the IPv6 header as well. /// </summary> public ushort Checksum { get { return (ushort)IPAddress.NetworkToHostOrder((short)icmpChecksum); } set { icmpChecksum = (ushort)IPAddress.HostToNetworkOrder((short)value); } }
/// <summary> /// This routine creates an instance of the Icmpv6Header class from a byte /// array that is a received IGMP packet. This is useful when a packet /// is received from the network and the header object needs to be /// constructed from those values. /// </summary> /// <param name="icmpv6Packet">Byte array containing the binary ICMPv6 header</param> /// <param name="bytesCopied">Number of bytes used in header</param> /// <returns>Returns the Icmpv6Header object created from the byte array</returns> static public Icmpv6Header Create(byte[ ] icmpv6Packet, ref int bytesCopied) { Icmpv6Header icmpv6Header = new Icmpv6Header(); int offset = 0;
// Verify buffer is large enough to contain an ICMPv6 header if (icmpv6Packet.Length < Icmpv6Header.Icmpv6HeaderLength) return null;
icmpv6Header.icmpType = icmpv6Packet[offset++]; icmpv6Header.icmpCode = icmpv6Packet[offset++]; icmpv6Header.icmpChecksum = BitConverter.ToUInt16(icmpv6Packet, offset); bytesCopied = Icmpv6Header.Icmpv6HeaderLength; return icmpv6Header; }
/// <summary> /// This routine builds the ICMPv6 packet and payload into a byte array. /// It also computes the IPv6 pseudo header checksum that appears in the /// ICMPv6 packet. /// </summary> /// <param name="payLoad">A byte array representing the ICMPv6 payload</param> /// <returns>A byte array of the ICMPv6 packet and payload</returns> public override byte[ ] GetProtocolPacketBytes(byte[ ] payLoad) { byte[ ] icmpv6Packet, pseudoHeader, byteValue; int offset = 0, payLoadLength;
// Build the ICMPv6 packet first since its required in the pseudo header calculation icmpv6Packet = new byte[Icmpv6HeaderLength + payLoad.Length];
offset = 0; icmpv6Packet[offset++] = icmpType; icmpv6Packet[offset++] = icmpCode; icmpv6Packet[offset++] = 0; icmpv6Packet[offset++] = 0;
// Copy the payload into the build ICMPv6 packet Array.Copy(payLoad, 0, icmpv6Packet, offset, payLoad.Length);
// Now build the pseudo header pseudoHeader = new byte[40 + icmpv6Packet.Length];
offset = 0;
byteValue = ipv6Header.SourceAddress.GetAddressBytes(); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
byteValue = ipv6Header.DestinationAddress.GetAddressBytes(); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
// Packet total length payLoadLength = IPAddress.HostToNetworkOrder(Icmpv6HeaderLength + payLoad.Length);
byteValue = BitConverter.GetBytes(payLoadLength); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
// 3 bytes of zero padding pseudoHeader[offset++] = (byte)0; pseudoHeader[offset++] = (byte)0; pseudoHeader[offset++] = (byte)0; pseudoHeader[offset++] = (byte)ipv6Header.NextHeader;
// Next is the icmpv6 header and its payload Array.Copy(icmpv6Packet, 0, pseudoHeader, offset, icmpv6Packet.Length); offset += icmpv6Packet.Length;
// Compute checksum on pseudo header Checksum = ComputeChecksum(pseudoHeader);
// Go back and put the checksum value into the marshalled byte array byteValue = BitConverter.GetBytes(icmpChecksum); Array.Copy(byteValue, 0, icmpv6Packet, 2, byteValue.Length); return icmpv6Packet; } } |
Next, add the ICMP for Ipv6 echo request class.
/// <summary> /// Class representing the ICMPv6 echo request header. Since the ICMPv6 protocol is /// used for a variety of different functions other than "ping", this header is /// broken out from the base ICMPv6 header that is common across all of its functions /// (such as Multicast Listener Discovery, Neighbor Discovery, etc.). /// </summary> class Icmpv6EchoRequest : ProtocolHeader { private ushort echoId; private ushort echoSequence;
static public int Icmpv6EchoRequestLength = 4;
/// <summary> /// Simple constructor for the ICMPv6 echo request header /// </summary> public Icmpv6EchoRequest() : base() { echoId = 0; echoSequence = 0; }
/// <summary> /// Gets and sets the ID field. Also performs the necessary byte order conversion. /// </summary> public ushort Id { get { return (ushort)IPAddress.NetworkToHostOrder((short)echoId); } set { echoId = (ushort)IPAddress.HostToNetworkOrder((short)value); } }
/// <summary> /// Gets and sets the echo sequence field. Also performs the necessary byte order conversion. /// </summary> public ushort Sequence { get { return (ushort)IPAddress.NetworkToHostOrder((short)echoSequence); } set { echoSequence = (ushort)IPAddress.HostToNetworkOrder((short)value); } }
/// <summary> /// This routine creates an instance of the Icmpv6EchoRequest class from a byte /// array that is a received IGMP packet. This is useful when a packet /// is received from the network and the header object needs to be /// constructed from those values. /// </summary> /// <param name="echoData">Byte array containing the binary ICMPv6 echo request header</param> /// <param name="bytesCopied">Number of bytes used in header</param> /// <returns>Returns the Icmpv6EchoRequest object created from the byte array</returns> static public Icmpv6EchoRequest Create(byte[ ] echoData, ref int bytesCopied) { Icmpv6EchoRequest icmpv6EchoRequestHeader = new Icmpv6EchoRequest();
// Verify buffer is large enough if (echoData.Length < Icmpv6EchoRequest.Icmpv6EchoRequestLength) return null;
// Properties are stored in network byte order so just grab the bytes // from the buffer icmpv6EchoRequestHeader.echoId = BitConverter.ToUInt16(echoData, 0); icmpv6EchoRequestHeader.echoSequence = BitConverter.ToUInt16(echoData, 2); bytesCopied = Icmpv6EchoRequest.Icmpv6EchoRequestLength; return icmpv6EchoRequestHeader; }
/// <summary> /// This method builds the byte array representation of the ICMPv6 echo request header /// as it would appear on the wire. /// </summary> /// <param name="payLoad">Payload to appear after the ICMPv6 echo request header</param> /// <returns>Returns the byte array representing the packet and payload</returns> public override byte[ ] GetProtocolPacketBytes(byte[] payLoad) { byte[ ] icmpv6EchoRequestHeader = new byte[Icmpv6EchoRequestLength + payLoad.Length], byteValue; int offset = 0;
byteValue = BitConverter.GetBytes(echoId); Array.Copy(byteValue, 0, icmpv6EchoRequestHeader, offset, byteValue.Length); offset += byteValue.Length; byteValue = BitConverter.GetBytes(echoSequence); Array.Copy(byteValue, 0, icmpv6EchoRequestHeader, offset, byteValue.Length); offset += byteValue.Length; Array.Copy(payLoad, 0, icmpv6EchoRequestHeader, offset, payLoad.Length);
return icmpv6EchoRequestHeader; } } |
Next, add the UDP header class definition.
class UdpHeader : ProtocolHeader { private ushort srcPort; private ushort destPort; private ushort udpLength; private ushort udpChecksum;
public Ipv6Header ipv6PacketHeader; public Ipv4Header ipv4PacketHeader;
static public int UdpHeaderLength = 8;
/// <summary> /// Simple constructor for the UDP header. /// </summary> public UdpHeader() : base() { srcPort = 0; destPort = 0; udpLength = 0; udpChecksum = 0;
ipv6PacketHeader = null; ipv4PacketHeader = null; }
/// <summary> /// Gets and sets the destination port. Performs the necessary byte order conversion. /// </summary> public ushort SourcePort { get { return (ushort)IPAddress.NetworkToHostOrder((short)srcPort); } set { srcPort = (ushort)IPAddress.HostToNetworkOrder((short)value); } }
/// <summary> /// Gets and sets the destination port. Performs the necessary byte order conversion. /// </summary> public ushort DestinationPort { get { return (ushort)IPAddress.NetworkToHostOrder((short)destPort); } set { destPort = (ushort)IPAddress.HostToNetworkOrder((short)value); } }
/// <summary> /// Gets and sets the UDP payload length. This is the length of the payload /// plus the size of the UDP header itself. /// </summary> public ushort Length { get { return (ushort)IPAddress.NetworkToHostOrder((short)udpLength); } set { udpLength = (ushort)IPAddress.HostToNetworkOrder((short)value); } }
/// <summary> /// Gets and sets the checksum value. It performs the necessary byte order conversion. /// </summary> public ushort Checksum { get { return (ushort)IPAddress.NetworkToHostOrder((short)udpChecksum); } set { udpChecksum = (ushort)IPAddress.HostToNetworkOrder((short)value); } }
/// <summary> /// /// </summary> /// <param name="udpData"></param> /// <param name="bytesCopied"></param> /// <returns></returns> static public UdpHeader Create(byte[] udpData, ref int bytesCopied) { UdpHeader udpPacketHeader = new UdpHeader();
udpPacketHeader.srcPort = BitConverter.ToUInt16(udpData, 0); udpPacketHeader.destPort = BitConverter.ToUInt16(udpData, 2); udpPacketHeader.udpLength = BitConverter.ToUInt16(udpData, 4); udpPacketHeader.udpChecksum = BitConverter.ToUInt16(udpData, 6);
return udpPacketHeader; }
/// <summary> /// This method builds the byte array representation of the UDP header as it would appear /// on the wire. To do this it must build the IPv4 or IPv6 pseudo header in order to /// calculate the checksum on the packet. This requires knowledge of the IPv4 or IPv6 header /// so one of these must be set before a UDP packet can be set. /// /// The IPv4 pseudo header consists of: /// 4-byte source IP address /// 4-byte destination address /// 1-byte zero field /// 1-byte protocol field /// 2-byte UDP length /// 2-byte source port /// 2-byte destination port /// 2-byte UDP packet length /// 2-byte UDP checksum (zero) /// UDP payload (padded to the next 16-bit boundary) /// The IPv6 pseudo header consists of: /// 16-byte source address /// 16-byte destination address /// 4-byte payload length /// 3-byte zero pad /// 1-byte protocol value /// 2-byte source port /// 2-byte destination port /// 2-byte UDP length /// 2-byte UDP checksum (zero) /// UDP payload (padded to the next 16-bit boundary) /// </summary> /// <param name="payLoad">Payload that follows the UDP header</param> /// <returns></returns> public override byte[ ] GetProtocolPacketBytes(byte[ ] payLoad) { byte[ ] udpPacket = new byte[UdpHeaderLength + payLoad.Length], pseudoHeader = null, byteValue = null; int offset = 0;
// Build the UDP packet first byteValue = BitConverter.GetBytes(srcPort); Array.Copy(byteValue, 0, udpPacket, offset, byteValue.Length); offset += byteValue.Length;
byteValue = BitConverter.GetBytes(destPort); Array.Copy(byteValue, 0, udpPacket, offset, byteValue.Length); offset += byteValue.Length;
byteValue = BitConverter.GetBytes(udpLength); Array.Copy(byteValue, 0, udpPacket, offset, byteValue.Length); offset += byteValue.Length;
udpPacket[offset++] = 0; // Checksum is initially zero udpPacket[offset++] = 0;
// Copy payload to end of packet Array.Copy(payLoad, 0, udpPacket, offset, payLoad.Length);
if (ipv4PacketHeader != null) { pseudoHeader = new byte[UdpHeaderLength + 12 + payLoad.Length];
// Build the IPv4 pseudo header offset = 0;
// Source address byteValue = ipv4PacketHeader.SourceAddress.GetAddressBytes(); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
// Destination address byteValue = ipv4PacketHeader.DestinationAddress.GetAddressBytes(); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
// 1 byte zero pad plus next header protocol value pseudoHeader[offset++] = 0; pseudoHeader[offset++] = ipv4PacketHeader.Protocol;
// Packet length byteValue = BitConverter.GetBytes(udpLength); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
// Copy the UDP packet to the end of this Array.Copy(udpPacket, 0, pseudoHeader, offset, udpPacket.Length); } else if (ipv6PacketHeader != null) { uint ipv6PayloadLength;
pseudoHeader = new byte[UdpHeaderLength + 40 + payLoad.Length];
// Build the IPv6 pseudo header offset = 0;
// Source address byteValue = ipv6PacketHeader.SourceAddress.GetAddressBytes(); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
// Destination address byteValue = ipv6PacketHeader.DestinationAddress.GetAddressBytes(); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
ipv6PayloadLength = (uint)IPAddress.HostToNetworkOrder((int)(payLoad.Length + UdpHeaderLength));
// Packet payload: ICMPv6 headers plus payload byteValue = BitConverter.GetBytes(ipv6PayloadLength); Array.Copy(byteValue, 0, pseudoHeader, offset, byteValue.Length); offset += byteValue.Length;
// 3 bytes zero pad plus next header protocol value pseudoHeader[offset++] = 0; pseudoHeader[offset++] = 0; pseudoHeader[offset++] = 0; pseudoHeader[offset++] = ipv6PacketHeader.NextHeader;
// Copy the UDP packet to the end of this Array.Copy(udpPacket, 0, pseudoHeader, offset, udpPacket.Length); }
if (pseudoHeader != null) { Checksum = ComputeChecksum(pseudoHeader); }
// Put checksum back into packet byteValue = BitConverter.GetBytes(udpChecksum); Array.Copy(byteValue, 0, udpPacket, 6, byteValue.Length);
return udpPacket; } } |
Build the project and make sure there is no error.
![]() |
|
You should see the generated DLL under the Debug folder that ready to be used.
We will use the Protocol.cs source file or the generated DLL for other projects later.