Raw Sockets


Another very useful socket type is SocketType.Raw , which is used by applications that need to build custom protocol headers encapsulated in the given transport protocol header, which in our case can either be an IPv4 or IPv6 header. A raw socket is created by creating a Socket object and specifying either IPv4 or IPv6, SocketType.Raw , and the ProtocolType of the protocol being built by the application. For example, if ProtocolType.Icmp is specified, any data sent on that socket is expected to have a valid ICMP protocol header followed by the data payload. Both the IPv4 and IPv6 headers contain an 8-bit value that identifies the next upper-layer protocol header that s set by the ProtocolType parameter to the Socket constructor. The ICMP and ICMPv6 protocols are defined in RFCs 792 and 2463, respectively.

After the raw socket is created, it must be bound to an explicit local interface before any operation can be performed on it. Once bound, it can be used to send and receive protocol-specific data, which we ll cover in the following sections.

A raw socket sample is provided under the Chap08\RawSocket folder that implements IPv4 and IPv6 ping as well as an IPv4 and IPv6 raw UDP sender.

Sending with Raw Sockets

To send data, the protocol header must be built correctly. A protocol header is defined by a series of bit fields that have distinct values with specific meanings. Figure 8-2 shows the ICMP header for the IPv4 protocol. Each field must be set to valid values for the remote host to respond. For example, to issue an ICMP echo request ( otherwise known as a ping ), the Type field is set to 8 while the Code field is set to 0. Also, the Checksum field must be correctly calculated. Protocol headers typically require the 16-bit one s complement checksum of the protocol header and any payload. (See the Chap08\RawSocket code sample for implementation details.) When a remote machine receives this packet, it sends back an ICMP echo response packet ( Type and Code both 0).

click to expand
Figure 8-2: ICMP protocol header

When building the protocol header, it s important to remember that all data must be converted to network byte order. Additionally, most values used by the Socket class that are related to the protocol (such as the IP address and port) are also subject to this rule. However, this conversion is hidden from the application because the constructors for these various object (such as IPAddress and IPEndPoint ) implicitly perform the necessary byte order conversion when getting and setting the values ”that is, when a value is assigned into the object, it s converted to network byte order, and when the value is retrieved, it s converted into host byte order.

An application can perform byte order conversion by using the static methods IPAddress.NetworkToHostOrder and IPAddress.HostToNetworkOrder . Each of these methods is overloaded to perform conversion on different basic types. The inputs supported are short , int , and long (or Short , Integer , and Long in Visual Basic .NET).

Note  

Unsigned variables passed into a byte order conversion function should be cast as the signed equivalent and cast back to the original unsigned type. Otherwise, the method mangles the resulting value. Additionally, the Unchecked operator may be used in C#.

Receiving with Raw Sockets

When receiving data on a raw socket, there are a few behavioral differences between IPv4 and IPv6 raw sockets. With IPv4, data received on the socket will include the IPv4 header, all subsequent headers, and the packet payload. With IPv6, data received on the raw socket will start with the protocol header following the IPv6 header; that is, a raw IPv6 socket will never receive the IPv6 header. Also, don t forget that the protocol headers returned from the receive call will be in network byte order and will require manual translation to host byte order when decoding the header.

A complete raw socket sample is located at Chap08\rawsocket\cs. The various protocol headers are defined in protocol.cs, while the process of sending and receiving a ping request is implemented in ping.cs.

Sample: IPv4 Raw Socket and ICMP

Let s look at how to create a raw socket and build the protocol header. In this example, we ll create an IPv4/ICMP echo request packet, which is the same thing ping.exe does to determine if a remote computer is alive and on the network. The associated code sample also performs IPv6/ICMPv6 echo requests .

  1. Create a raw IPv4 socket and specify the ICMP protocol, as shown here:

    C#

     SocketrawSocket=newSocket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp); 

    Visual Basic .NET

     DimrawSocketAsSocket=NewSocket(_ AddressFamily.InterNetwork,_ SocketType.Raw,_ ProtocolType.Icmp_) 
  2. Bind the raw socket to an explicit local interface. In this example, the interface is 10.10.10.1. Because the ICMP protocol does not contain port fields, the IPEndPoint is created by specifying zero for the port.

    C#

     IPEndPointbindEndPoint=newIPEndPoint(IPAddress.Parse(10.10.10.1), 0); rawSocket.Bind(bindEndPoint); 

    Visual Basic .NET

     DimbindEndPointAsIPEndPoint=NewIPEndPoint(_ IPAddress.Parse(10.10.10.1),_ 0_) rawSocket.Bind(bindEndPoint) 
  3. Build the ICMP and echo request header. A byte array is allocated to contain the 4-byte ICMP base header plus another 4 bytes for the echo request header followed by a 32-byte payload. The Checksum field is initially set to 0. For the Identifier field, we use the process ID, which is used to verify that any responses received are responses to our requests (because the echo reply will use the same identifier).

    C#

     byte[]icmpData=newbyte[40], byteArray; intoffset=0; shorticmpIdentifier=0, icmpSequence=IPAddress.HostToNetworkOrder((short)1); System.Diagnostics.Processproc= System.Diagnostics.Process.GetCurrentProcess(); icmpIdentifier=IPAddress.HostToNetworkOrder((short)proc.Id); icmpData[offset++]=(byte)8;//ICMPechorequesttype icmpData[offset++]=(byte)0;//ICMPechorequestcode icmpData[offset++]=0;//Checksumsettozero icmpData[offset++]=0; byteArray=BitConverter.GetBytes(IPAddress.HostToNetworkOrder(icmpIdentifier)); Array.Copy(byteArray,0,icmpData,offset,byteArray.Length); offset+=byteArray.Length; byteArray=BitConverter.GetBytes(IPAddress.HostToNetworkOrder(icmpSequence)); Array.Copy(byteArray,0,icmpData,offset,byteArray.Length); for(;offset<icmpData.Length;offset++) icmpData[offset]=(byte)e; 

    Visual Basic .NET

     DimicmpData(40)AsByte DimbyteArray()AsByte DimoffsetAsInteger=0 DimicmpIdentifierAsShort=0 DimicmpSequenceAsShort=IPAddress.HostToNetworkOrder(CShort(1)) DimprocAsSystem.Diagnostics.Process=_ System.Diagnostics.Process.GetCurrentPRocess() icmpIdentifier=IPAddress.HostToNetworkOrder(CShort(proc.Id)) icmpData(offset)=8ICMPechorequesttype offset=offset+1 icmpData(offset)=0ICMPechorequestcode offset=offset+1 icmpData(offset)=0Checksumsettozero offset=offset+1 icmpData(offset)=0 offset=offset+1 byteArray=BitConverter.GetBytes(_ IPAddress.HostToNetworkOrder(icmpIdentifier)) Array.Copy(byteArray,0,icmpData,offset,byteArray.Length) offset=offset+byteArray.Length byteArray=BitConverter.GetBytes(_ IPAddress.HostToNetworkOrder(icmpSequence)) Array.Copy(byteArray,0,icmpData,offset,byteArray.Length) offset=offset+byteArray.Length 
  4. Compute the checksum. The following method computes the 16-bit one s complement checksum on a byte array. Assume that this static method is a member of the class ProtocolHeader .

    C#

     staticpublicushortComputeChecksum(byte[]payLoad) { uintxsum=0; ushortshortval=0, hiword=0, loword=0; //Sumupthe16-bits for(inti=0;i<payLoad.Length/2;i++) { hiword=(ushort)(((ushort)payLoad[i*2])<<8); loword=(ushort)payLoad[(i*2)+1]; shortval=(ushort)(hiwordloword); xsum=xsum+(uint)shortval; } //Padthelastbyteifnecessary if((payLoad.Length%2)!=0) { xsum+=(uint)payLoad[payLoad.Length-1]; } xsum=((xsum>>16)+(xsum&0xFFFF)); xsum=(xsum+(xsum>>16)); shortval=(ushort)(~xsum); returnshortval; } 
  5. Call the checksum routine, and assign the value into the ICMP packet.

    C#

     ushortchecksumValue; //Computethechecksum checksumValue=ProtocolHeader.ComputeChecksum(icmpData); //AssignvaluebackintoICMPpacket byteArray=BitConverter.GetBytes(IPAddress.HostToNetworkOrder(checksumValue)); Array.Copy(byteArray,0,icmpData,3,byteArray.Length); 

    Visual Basic .NET

     DimchecksumValueAsUInt16 


Network Programming for the Microsoft. NET Framework
Network Programming for the MicrosoftВ® .NET Framework (Pro-Developer)
ISBN: 073561959X
EAN: 2147483647
Year: 2003
Pages: 121

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net