Finally, add the UDP header definition class.
public ref class UdpHeader : ProtocolHeader { private: unsigned short srcPort; unsigned short destPort; unsigned short udpLength; unsigned short udpChecksum;
public: Ipv6Header^ ipv6PacketHeader; Ipv4Header^ ipv4PacketHeader; static int UdpHeaderLength = 8;
/// <summary> /// Simple constructor for the UDP header. /// </summary> public: UdpHeader() { srcPort = 0; destPort = 0; udpLength = 0; udpChecksum = 0; ipv6PacketHeader = nullptr; ipv4PacketHeader = nullptr; }
/// <summary> /// Gets and sets the destination port. Performs the necessary byte order conversion. /// </summary> public: property unsigned short SourcePort { unsigned short get() { return (unsigned short)IPAddress::NetworkToHostOrder((short)srcPort); } void set(unsigned short value) { srcPort = (unsigned short)IPAddress::HostToNetworkOrder((short)value); } }
/// <summary> /// Gets and sets the destination port. Performs the necessary byte order conversion. /// </summary> public: property unsigned short DestinationPort { unsigned short get() { return (unsigned short)IPAddress::NetworkToHostOrder((short)destPort); } void set(unsigned short value) { destPort = (unsigned short)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: property unsigned short Length { unsigned short get() { return (unsigned short)IPAddress::NetworkToHostOrder((short)udpLength); } void set(unsigned short value) { udpLength = (unsigned short)IPAddress::HostToNetworkOrder((short)value); } }
/// <summary> /// Gets and sets the checksum value. It performs the necessary byte order conversion. /// </summary> public: property unsigned short Checksum { unsigned short get() { return (unsigned short)IPAddress::NetworkToHostOrder((short)udpChecksum); } void set(unsigned short value) { udpChecksum = (unsigned short)IPAddress::HostToNetworkOrder((short)value); } }
/// <summary> /// /// </summary> /// <param name="udpData"></param> /// <param name="bytesCopied"></param> /// <returns></returns> public: static UdpHeader^ Create(array<Byte>^ udpData, int bytesCopied) { UdpHeader^ udpPacketHeader = gcnew 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: virtual array<Byte>^ GetProtocolPacketBytes(array<Byte>^ payLoad) override { array<Byte>^ udpPacket = gcnew array<Byte>(UdpHeaderLength + payLoad->Length); array<Byte>^ pseudoHeader = nullptr; array<Byte>^ byteValue = nullptr; 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 != nullptr) { pseudoHeader = gcnew array<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 != nullptr) { unsigned int ipv6PayloadLength; pseudoHeader = gcnew array<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 = (unsigned int)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 != nullptr) { Checksum = ComputeChecksum(pseudoHeader); }
// Put checksum back into packet byteValue = BitConverter::GetBytes(udpChecksum); Array::Copy(byteValue, 0, udpPacket, 6, byteValue->Length); return udpPacket; } }; } |
Well, finally we managed to complete this protocol header definition. Make sure there is no matching braces missing. Build the project and make sure there is no error.
You should see the generated DLL under the Debug folder. We will use the generated DLL in other exercises later.