The tutorial you are reading is: Dialysis ICMP protocol (5): Applying route tracing.
Principles:
--------
Through the introduction in the first four sections, you may have a preliminary understanding of ICMP applications. but before this section, I will introduce the ICMP protocol from a macro perspective. as we all know, ICMP is the third layer of iso-the network layer. Since it is at the same layer as the IP protocol, we may only use the IP protocol. Therefore, some books say that the Layer 4 of the ICMP bit ISO is wrong. The examples shown in those books are also incorrect. I found that the materials of a foreign communication company have two incorrect methods.
--------------------------
| ICMP | TCP (sctp) |
--------------------------
| IP |
--------------------------
---------------------------
|... | TCP (sctp) |
---------------------------
| ICMP | IP |
----------------------------
In fact, the above method is incorrect. The correct method should be:
---------------------
|... | TCP (sctp) |
---------------------
| ICMP |
---------- |
| IP |
---------------------
Next, let's explain how to implement the tracking routing function. You may have learned the specific content of timeout packets through reading in section 1 (refer to dialysis ICMP protocol (I ): protocol principle). If the gateway finds that the TTL is zero when processing data reports, the datagram must be discarded. The gateway must also notify the source host through timeout information. This is the specific structure of its message:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 4 5 6 7 8 9 0 1
+- +-+
| Type (11) | code (0/1) | checksum |
+- +-+
| Unused |
+- +-+
| Internet header + 64 bits of original data datasync |
+- +-+
You can use the setsockopt () function to set the TTL field in the IP packet header of an ICMP packet. The specific process is as follows. Assume that your IP address needs N routers (n> 1) to reach the target address ). Then
1. initialize the first ICMP packet and set TTL to 1 in the IP address header. The timeout packet sent back by the first data router is obtained.
2. Generally, initialize the I (I <n) ICMP packet and set the TTL in the IP address header to I. Then, the timeout packet sent back by the first data router is obtained.
The remaining problem is how to determine the router IP address of the timeout ICMP packet to obtain its machine name information. Many readers may ask this question and use gethostbyaddr () to obtain the answer.
After theoretical arguments, let's look at how to implement it.
Specific implementation: (how to first try ICMP data packets has been described in detail in the previous section. Here we just add the routing tracing code)
--------
The main code is as follows:
Unsigned long ipback = 0; // the IP address of the timeout packet.
Unsigned long MS = 0; // timeout value
Struct hostent * hhost;
Char m_address [2, 256];
// Wait until the target host is found or the maximum hop count (hops) is reached)
While (ipback! = Ipfinal ){
Hhost = 0;
// Send ping packets to a vro in the middle of the target host (TTL is 1 ~ N-1)
If (Ping (m_address, TTL, ipback, MS ))
{
Sin. sin_family = af_inet;
Sin. sin_addr.s_un.s_addr = ipback; // ip address returned by the function
// Find the host name
Hhost = gethostbyaddr (char *) & sin. sin_addr, 4, pf_inet );
// The hhost content can be output here
}
TTL ++;
If (TTL> max_hops) // reach the maximum number of hops
{
Break;
}
}
============================
Ping function code
============================
Int Ping (const char * Host, int TTL, unsigned long & ipback, unsigned long & MS)
{
Socket sockraw;
Struct sockaddr_in DEST, from;
Struct hostent * HP;
Int bread, datasize;
Int fromlen = sizeof (from );
Int timeout = 100;
Char * dest_ip;
Char * icmp_data;
Char * recvbuf;
Unsigned int ADDR = 0;
Const int max_packet= 1024;
// Initialize the socket
Sockraw = wsasocket (af_inet,
Sock_raw,
Ipproto_icmp,
Null, 0, wsa_flag_overlapped );
If (sockraw = invalid_socket)
{
// Error
}
// Set the TTL field of the IP Address Header
Bread = setsockopt (sockraw, ipproto_ip, ip_ttl, (char *) & TTL, sizeof (INT ));
If (bread = socket_error)
{
// Error
}
// Set the accept timeout value to 100 ms
Bread = setsockopt (sockraw, sol_socket, so_rcvtimeo, (char *) & timeout, sizeof (timeout ));
If (bread = socket_error)
{
// Error
}
// Disable the use of the Nagle algorithm to cache data
Bread = setsockopt (sockraw, sol_socket, tcp_nodelay, (const char *) & killnagle, sizeof (INT ));
If (bread = socket_error)
{
// Error
}
Timeout = 1000;
// Set the sending timeout value to 100 ms
Bread = setsockopt (sockraw, sol_socket, so_sndtimeo, (char *) & timeout,
Sizeof (timeout ));
If (bread = socket_error)
{
// Error
}
// The following code generates an ICMP Packet
Memset (& DEST, 0, sizeof (DEST ));
HP = gethostbyname (host );
If (! HP)
{
ADDR = inet_addr (host );
}
If ((! HP) & (ADDR = inaddr_none ))
{
// Error
}
If (HP! = NULL)
Memcpy (& (DEST. sin_addr), HP-> h_addr, HP-> h_length );
Else
DeST. sin_addr.s_addr = ADDR;
// Initialize dest
If (HP)
DeST. sin_family = hp-> h_addrtype;
Else
DeST. sin_family = af_inet;
Dest_ip = inet_ntoa (DEST. sin_addr );
// Set the package Length
Datasize = def_packet_size;
// Calculate the package size
Datasize + = sizeof (icmpheader );
Icmp_data = (char *) New [max_packet]; // allocates memory. You can use new and delete
Recvbuf = (char *) New [max_packet];
If (! Icmp_data)
{
// Release the memory and exit
}
If (! Recvbuf)
{
// Release the memory and exit}
}
Memset (icmp_data, 0, max_packet );
Fill_icmp_data (icmp_data, datasize); // This function is used to fill ICMP data packets.
Int bwrote;
(Icmpheader *) icmp_data)-> I _cksum = 0;
(Icmpheader *) icmp_data)-> timestamp = gettickcount (); // Save the current time value
(Icmpheader *) icmp_data)-> I _seq = seq_no ++;
// Calculate the checksum
(Icmpheader *) icmp_data)-> I _cksum = checksum (ushort *) icmp_data, datasize );
// Calculate the total time for returning the ICMP Packet
Unsigned long Tc = gettickcount ();
// Send data packets
Bwrote = sendto (sockraw, icmp_data, datasize, 0, (struct sockaddr *) & DEST, sizeof (DEST ));
If (bwrote = socket_error)
{
// Error
}
If (bwrote <datasize) // Number of sent bytes pair No
{
}
// Accept data packets
Bread = recvfrom (sockraw, recvbuf, max_packet, 0, (struct sockaddr *) & from,
& Fromlen );
// Calculate the total time
MS = gettickcount ()-TC;
If (bread = socket_error)
{
// Error
}
// Obtain the returned vro
Ipback = from. sin_addr.s_addr;
Return 1;
}
====================================
Source code of function fill_icmp_data ()
====================================
// This structure will be used below
Typedef struct _ ihdr {
Byte I _type;
Byte I _code;
Ushort I _cksum;
Ushort I _id;
Ushort I _seq;
Ulong timestamp;/* this is not part of the ICMP packet, just to calculate the time */
} Icmpheader;
Void fill_icmp_data (char * icmp_data, int datasize ){
Icmpheader * icmp_hdr;
Char * datapart;
Icmp_hdr = (icmpheader *) icmp_data;
Icmp_hdr-> I _type = ICMP_Echo;
Icmp_hdr-> I _code = 0;
Icmp_hdr-> I _id = (ushort) getcurrentprocessid ();
Icmp_hdr-> I _cksum = 0;
Icmp_hdr-> I _seq = 0;
Datapart = icmp_data + sizeof (icmpheader); // calculate the start address of the data domain
// Initial trial data domain
Memset (datapart, 'E', datasize-sizeof (icmpheader ));
}