March 24, 2011, 2:44 p.m.
posted by vendetta
Using Raw Sockets
Because ICMP packets do not use either TCP or UDP, you cannot use either of the socket helper classes, TcpClient or UdpClient. Instead, you have to use what are called raw sockets, which are a feature of the Socket class. Raw sockets allow you to define your own network packet above the IP layer. Of course, this means that you must do all the work of manually creating all the individual fields in the ICMP packet, rather than having the .NET library create the packet for you, as it does with TCP and UDP.
Raw Sockets Format
To create a raw socket, you must use the SocketType.Raw socket type when the socket is created. There are several ProtocolType values that you can use to match with the raw socket type; they’re listed in Figure.
|
Value |
Description |
|---|---|
|
Ggp |
Gateway-to-Gateway Protocol |
|
Icmp |
Internet Control Message Protocol |
|
Idp |
IDP Protocol |
|
Igmp |
Internet Group Management Protocol |
|
IP |
A raw IP packet |
|
Ipx |
Novell IPX Protocol |
|
ND |
Net Disk Protocol |
|
Pup |
Xerox PARC Universal Protocol (PUP) |
|
Raw |
A raw IP packet |
|
Spx |
Novell SPX Protocol |
|
SpxII |
Novell SPX Version 2 Protocol |
|
Unknown |
An unknown protocol |
|
Unspecified |
An unspecified protocol |
The specific protocols listed for a raw socket allows the .NET library to properly create the underlying IP packet. By using the ProtocolType.Icmp value, the IP packet created by the socket defines the next layer protocol as ICMP (IP value Type 1). This allows the remote host to immediately identify the packet as an ICMP packet, and process it accordingly.
Obviously, for the applications in this chapter, you will use the ProtocolType.Icmp value. Here’s the command to create a socket for ICMP packets:
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
Sending Raw Packets
Because ICMP is a connectionless protocol, you do not have to bind the socket to a specific local port to send a packet or use the Connect() method to connect it to a specific remote host. You must use the SendTo() method to specify the IPEndPoint object of the destination address. ICMP does not use ports, so the value of the port property of the IPEndPoint object is not important. The following creates an IPEndPoint destination object with no port and sends a packet to it:
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("192.168.1.2"), 0);
sock.SendTo(packet, iep);
Receiving Raw Packets
Receiving data from a raw socket is trickier than sending data in a raw socket. To receive data from the raw socket, you must use the ReceiveFrom() method. Because the raw socket does not identify a higher-layer protocol, the data returned from a ReceiveFrom() method call contains the entire IP packet contents. You must extract the data from the raw IP packet information to create the ICMP packet elements. As you can see in Figure, the IP packet data starts at byte 20. Therefore, to extract the ICMP packet data and header, you start reading the byte array at the 20th position in the received data packet.
| Warning |
Because the ReceiveFrom() method returns the entire IP packet, you must remember to declare the receiving buffer size to be at least 20 bytes larger than your expected data. |