|
C++ Raw UDP Socket Program Example
Create a new CLR console application project and you might use the project and solution names as shown in the following Figure.
Add/edit the following using directives at the top of the file. |
using namespace System; using namespace System::Net; using namespace System::Net::Sockets; using namespace System::Collections; // Reference to the protocol header classes using namespace ProtocolHeaderDefinitionCP; |
Then, add the reference to the header definition in the project.
Build the project to make sure the reference to the ProtocolHeaderDefinitionCP is working.
Make sure there is no build error.
Then, adds the following usage() function.
static void usage() { Console::WriteLine("Usage: Executable_file_name [-as source-addr] [-ad dest-addr] [-ps source-port]"); Console::WriteLine(" [-pd dest-port] [-x payload-size] [-n send-count] [-b bind-addr]"); Console::WriteLine("Available Options:"); Console::WriteLine(" -as source-addr Source address for IP packet"); Console::WriteLine(" -ad dest-addr Destination address for IP packet"); Console::WriteLine(" -ps source-port Source port for UDP packet"); Console::WriteLine(" -pd dest-port Destination port for UDP packet"); Console::WriteLine(" -b bind-addr Local address to bind raw socket to"); Console::WriteLine(" -x payload-size Number of bytes for UDP payload"); Console::WriteLine(" -n send-count Number of times to send packet"); } |
Next, add the main() code.
int main(array<System::String ^> ^args) { // Default/initial values, the source should be a spoofed IP :-) IPAddress^ sourceAddress = IPAddress::Parse("1.1.1.1" ); IPAddress^ destAddress = IPAddress::Parse("2.2.2.2" ); IPAddress^ bindAddress = IPAddress::Any; unsigned short sourcePort = 5150, destPort = 1234; int messageSize = 16, sendCount = 5;
// Parse the command line if(args->Length != 0) { for(int i=0; i < args->Length ;i++) { try { if ( ( args[i][0] == '-' ) || ( args[i][0] == '/' ) ) { switch ( Char::ToLower( args[i][1] ) ) { case 'a': // Address parameter: source or destination if ( Char::ToLower( args[i][2] ) == 's' ) { sourceAddress = IPAddress::Parse( args[ ++i ]->ToString() ); } else if ( Char::ToLower( args[i][2] ) == 'd' ) { destAddress = IPAddress::Parse( args[ ++i ]->ToString() ); } else { usage(); return 0; } break; case 'b': // Local address to bind the socket to bindAddress = IPAddress::Parse( args[ ++i ]->ToString() ); break; case 'p': // Port parameter: source or destination if ( Char::ToLower( args[i][2] ) == 's' ) { sourcePort = Convert::ToUInt16( args[ ++i ]->ToString() ); } else if ( Char::ToLower( args[i][2] ) == 'd' ) { destPort = Convert::ToUInt16( args[ ++i ]->ToString() ); } else { usage(); return 0; } break; case 'x': // Size of message to send messageSize = Convert::ToInt32( args[ ++i ]->ToString() ); break; case 'n': // Number of times to send message sendCount = Convert::ToInt32( args[ ++i ]->ToString() ); break; default: usage(); return 0; } } } catch(Exception^ err) { Console::WriteLine("Error lol!: " + err->Message); usage(); return 0; } } } else { usage(); return 0; }
// Make sure parameters are consistent if ( ( sourceAddress->AddressFamily != destAddress->AddressFamily ) || ( sourceAddress->AddressFamily != bindAddress->AddressFamily) ) { Console::WriteLine("Source and destination address families don't match!"); usage(); return 0; }
// Print the command line parameters Console::WriteLine("Source address : {0} \tPort: {1}", sourceAddress->ToString(), sourcePort.ToString() ); Console::WriteLine("Dest address : {0} \tPort: {1}", destAddress->ToString(), destPort.ToString() ); Console::WriteLine("Local interface: {0}", bindAddress->ToString() ); Console::WriteLine("Message size : {0}", messageSize); Console::WriteLine("Send count : {0}", sendCount);
// Start building the headers Console::WriteLine("Building the packet header..."); array<Byte>^ builtPacket; array<Byte>^ payLoad = gcnew array<Byte>(messageSize); UdpHeader^ udpPacket = gcnew UdpHeader(); ArrayList^ headerList = gcnew ArrayList(); Socket^ rawSocket = nullptr; SocketOptionLevel socketLevel = SocketOptionLevel::IP;
// Initialize the payload Console::WriteLine("Initialize the payload..."); for(int i=0; i < payLoad->Length ;i++) payLoad[i] = (Byte) '#';
// Fill out the UDP header first Console::WriteLine("Filling out the UDP header..."); udpPacket->SourcePort = sourcePort; udpPacket->DestinationPort = destPort; udpPacket->Length = (unsigned short)(UdpHeader::UdpHeaderLength + messageSize); udpPacket->Checksum = 0;
if ( sourceAddress->AddressFamily == AddressFamily::InterNetwork ) { Ipv4Header^ ipv4Packet = gcnew Ipv4Header();
// Build the IPv4 header Console::WriteLine("Building the IPv4 header..."); ipv4Packet->Version = 4; ipv4Packet->Protocol = (Byte) ProtocolType::Udp; ipv4Packet->Ttl = 2; ipv4Packet->Offset = 0; ipv4Packet->Length = (Byte) Ipv4Header::Ipv4HeaderLength; ipv4Packet->TotalLength = (unsigned short) Convert::ToUInt16( Ipv4Header::Ipv4HeaderLength + UdpHeader::UdpHeaderLength + messageSize ); ipv4Packet->SourceAddress = sourceAddress; ipv4Packet->DestinationAddress = destAddress;
// Set the IPv4 header in the UDP header since it is required to calculate the // pseudo header checksum Console::WriteLine("Setting the IPv4 header for pseudo header checksum..."); udpPacket->ipv4PacketHeader = ipv4Packet;
// Add IPv4 header to list of headers -- headers should be added in th order // they appear in the packet (i.e. IP first then UDP) Console::WriteLine("Adding the IPv4 header to the list of header, encapsulating packet..."); headerList->Add( ipv4Packet );
socketLevel = SocketOptionLevel::IP; } else if ( sourceAddress->AddressFamily == AddressFamily::InterNetworkV6 ) { Ipv6Header^ ipv6Packet = gcnew Ipv6Header();
// Build the IPv6 header Console::WriteLine("Building the IPv6 header..."); ipv6Packet->Version = 6; ipv6Packet->TrafficClass = 1; ipv6Packet->Flow = 2; ipv6Packet->HopLimit = 2; ipv6Packet->NextHeader = (Byte) ProtocolType::Udp; ipv6Packet->PayloadLength = (unsigned short) ( UdpHeader::UdpHeaderLength + payLoad->Length ); ipv6Packet->SourceAddress = sourceAddress; ipv6Packet->DestinationAddress = destAddress;
// Set the IPv6 header in the UDP header since it is required to calculate the // pseudo header checksum Console::WriteLine("Setting the IPv6 header for pseudo header checksum..."); udpPacket->ipv6PacketHeader = ipv6Packet;
// Add the IPv6 header to the list of headers - headers should be added in the order // they appear in the packet (i.e. IP first then UDP) Console::WriteLine("Adding the IPv6 header to the list of header, encapsulating packet..."); headerList->Add( ipv6Packet ); socketLevel = SocketOptionLevel::IPv6; }
// Add the UDP header to list of headers after the IP header has been added Console::WriteLine("Adding the UDP header to the list of header, after IP header..."); headerList->Add( udpPacket );
// Convert the header classes into the binary on-the-wire representation Console::WriteLine("Converting the header classes into the binary..."); builtPacket = udpPacket->BuildPacket( headerList, payLoad );
// Create the raw socket for this packet Console::WriteLine("Creating the raw socket using Socket()..."); rawSocket = gcnew Socket(sourceAddress->AddressFamily, SocketType::Raw, ProtocolType::Udp);
// Bind the socket to the interface specified Console::WriteLine("Binding the socket to the specified interface using Bind()..."); rawSocket->Bind(gcnew IPEndPoint( bindAddress, 0 ) );
// Set the HeaderIncluded option since we include the IP header Console::WriteLine("Setting the HeaderIncluded option for IP header..."); rawSocket->SetSocketOption( socketLevel, SocketOptionName::HeaderIncluded, 1 ); try { // Send the packet! Console::WriteLine("Sending the packet..."); for (int i = 0; i < sendCount; i++) { int rc = rawSocket->SendTo(builtPacket, gcnew IPEndPoint(destAddress, destPort)); Console::WriteLine("send {0} bytes to {1}", rc, destAddress->ToString()); } } catch (SocketException^ err) { Console::WriteLine("Socket error occurred: {0}", err->Message); // http://msdn.microsoft.com/en-us/library/ms740668.aspx } finally { // Close the socket Console::WriteLine("Closing the socket..."); rawSocket->Close(); } return 0; } |
Next, build the project and make sure there is no error. Then, run the project. Any error will be thrown by the exception handlers.
The following is the sample output.