Dialysis ICMP Protocol (4): Niu Cheer First Try Second Application Ping (Raw Socket) ============================== This Article from Bugfree / 9CBS platform: VC6 Windows XP
After a cup of tea tonight, let's continue our ICMP discussion, introducing the PING program implemented with the RAW Socket tonight.
Principle: -------- Ping implemented by Raw Socket may be larger than the application ICMP.dll of the previous section, but this is something we need to pay attention to, my point of view really wants to do network development The programmer should calm down to read this article, I believe you will benefit a lot, I will explain some of the routing tracking of some things to the last chapter to do some paving. Another important thing to talk about, Microsoft Announced the development interface used by the last section, but this section is more general. So it will not be outdated, even small changes can be transplanted to other systems. System transplantation Not our focus. But Microsoft's long-term support is enough to cause us to fully pay. How to make changes to make this program to implement the function of tracking routes, just throwing brick 引 玉. Browing the IP package of IP packets in the ICMP package should be specific The value can get the router IP (requires the number of hops to reach the destination than your specific value). This program requires the permissions of the Windows2K / WindowsXP / WindowsNT platform and system administrators.
Specific implementation: -------- This source code is mostly from: http://tangentsoft.net/wskfaq/examples/rawping.html[bugfree] Only a small amount of modifications, give a lot of comments, Finally, combined with experience gives its own recommendations.
------------
/ * * Program Name: Rawping_Driver.cpp * Description: * Driver, also the main function * / # include
#include "rawping.h"
#define DEFAULT_PACKET_SIZE 32 // default ICMP packet bytes #define DEFAULT_TTL 30 // // default maximum block 1024 #define MAX_PING_PACKET_SIZE (MAX_PING_DATA_SIZE sizeof (IPHeader)) // Maximum ICMP TTL value of the packet length #define MAX_PING_DATA_SIZE
/ * * Send_buf allocated memory size and recv_buf send_buf to packet_size * recv_buf size MAX_PING_PACKET_SIZE, to ensure greater than send_buf * / int allocate_buffers (ICMPHeader * & send_buf, IPHeader * & recv_buf, int packet_size);
///// Program Entry Point
INT Main (int Argc, char * argv []) {INT seq_no = 0; // uses Icmpheader * send_buf = 0 in transmit and accepted ICMP classes; ipHeader * Recv_buf = 0;
/ / Judgment whether the command line is legal if (Argc <2) {CERR << "usage:" << argv [0] <<
// Start Winsock Wsadata WSADATA; IF (WsaStartup (MakeWord (2, 1), & WSADATA! = 0) {CERR << "Failed to Find Winsock 2.1 or better." << end1; return 1;}
SOCKET SD; // Raw Socket Handle SOCKADDR_IN DEST, SOURCE; // Three Tasks (Create SD, Set TTL, Try Dest) IF (Setup_for_Ping (Argv [1], TTL, SD, DEST) <0) {GOTO Cleanup; // Release resource and exit} // Distributes memory IF for Send_BUF and RECV_BUF (allocate_buff, recv_buf, packet_size <0) {goto cleanup;} // primarily IMCP packet (Type = 8, Code = 0 ) Init_ping_packet (send_buf, packet_size, seq_no);
/ / Send ICMP Packet IF (send_ping (SD, DEST, Send_buf, Packet_SIZE)> = 0) {while (1) {// Accept response package IF (Recv_ping (SD, SOURCE, RECV_BUF, MAX_PING_PACKET_SIZE) <0) {/ / Pull the sequence number out of the ICMP header If // it's bad, we just complain, but otherwise we take // off, because the read failed for some reason unsigned short header_len = recv_buf-> h_len * 4;.. ICMPHeader * ICMPHDR = (iCMPHEADER *) ((char *) Recv_buf header_len); if (ICMphDR-> SEQ! = seq_no) {CERR << "Bad sequence number!" << endl; continue;} else {brenue;}} (decode_reply (recv_buf, packet_size, & source)! = -2) {// Success or Fatal Error (as opposed to a minor error) // so take off. Break ;}}} Cleanup: delete [] send_buf; // Release the allocated memory delete [] Recv_buf; wsacleanup (); // Clean Winsock Return 0;}
// allocate memory for the send_buf and recv_buf of Too simple, I will skip int allocate_buffers (ICMPHeader * & send_buf, IPHeader * & recv_buf, int packet_size) {// First the send buffer send_buf = (ICMPHeader *) new char [packet_size] ; If (send_buf == 0) {CERR << "failed to allocate output buffer." << endl; return -1;}
// and tell = (ipHeader *) new char [MAX_PING_PACKET_SIZE]; if (Recv_buf == 0) {CERR << "Failed to Allocate Output Buffer." << Endl; Return -1;} Return 0; } / * * Program name: Rawping.h * Description: * Main function library header file * /
#define Win32_Lean_and_mean # include
// ICMP package type, specifically see the first section of this article #define ICMP_ECHO_REPLY 0 #define ICMP_DEST_UNREACH 3 # Define ICMP_TTL_EXPIRE 11 # define icmp_echo_request 8
// Minimum ICMP package size #define ICMP_MIN 8
// ip Baotou struct ipheader {byte h_len: 4; // length of the header in dwords byte version: 4; // version of ip byte Tos; // type of service ushort total_len; // length of the packet in dwords ushort Ident; // unique identifier ushort flags; // flags byte ttl; // time to live, I am used in the next section to implement Tracert function BYTE Proto; // Protocol Number (TCP, UDP ETC) Ushort Checksum; / / Ip Checksum Ulong Source_ip; ulong dest_ip;};
// ICMP Baotou (the actual package does not include the TimeStamp field, // The author is used to calculate the response time of the package, in fact, there is no need to do this) struct icmpheader {byte type; // ICMP packet type byte code; // type sub code; // Type Sub code Ushort checksum; ushort id; ushort seq; ulong timestamp; // NOT Part of ICMP, But we need it};
extern USHORT ip_checksum (USHORT * buffer, int size); extern int setup_for_ping (char * host, int ttl, SOCKET & sd, sockaddr_in & dest); extern int send_ping (SOCKET sd, const sockaddr_in & dest, ICMPHeader * send_buf, int packet_size); extern int recv_ping (SOCKET sd, sockaddr_in & source, IPHeader * recv_buf, int packet_size); extern int decode_reply (IPHeader * reply, int bytes, sockaddr_in * from); extern void init_ping_packet (ICMPHeader * icmp_hdr, int packet_size, int seq_no); / * * Program name: Rawping.cpp * Description: * Main function library implementation part * / include
// do a little shuffling cksum = (CKSUM >> 16) (CKSUM & 0xFFF); CKSUM = (CKSUM >> 16); // Return The bitwise complement of the resulting mishmash return (~ cksum); }
// Test Raw Socket, set TTL, primary test DEST // return value <0 table failed
INT setup_for_ping (char * host, int TTL, Socket & SD, SockAddr_in & DEST) {// create the socket sd = wsasocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, 0); if (SD == invalid_socket) {CERR << "Failed to create raw socket:" << wsagetlasterror () << endl; return -1;}
IF (setsockopt (SD, IPPROTO_IP, IP_TTTL, (const char *) & ttl, sizeof (ttl)) == Socket_ERROR) {CERR << "TTL SetsockOpt Failed:" Wsagetlasterror () << endl; return -1;} // Initialize The Destination Host Info Block Memset (& DEST, 0, SIZEOF (DEST);
// Turn first passed parameter into an IP address to ping unsigned int addr = inet_addr (host); if (! Addr = INADDR_NONE) {// It was a dotted quad number, so save result dest.sin_addr.s_addr = addr; dest .SIN_FAMILY = AF_INET;} else {// Not in dotted quad form, so try and look it up hostent * hp = gethostbyname (host); if (hp! = 0) {// Found an address for That Host, SO SAVE IT Memcpy (& (dest.sin_addr), hp-> h_addr, hp-> h_length); dest.sin_family = hp-> h_addrtype;} else {// not a recognized hostname Either! cerr << "failed to resolve" < Return 0;} / / Try the ICMP's header, fill the data part of the DATA, and finally calculate the checksum of the entire package. void init_ping_packet (ICMPHeader * icmp_hdr, int packet_size, int seq_no) {// Set up the packet's fields icmp_hdr-> type = ICMP_ECHO_REQUEST; icmp_hdr-> code = 0; icmp_hdr-> checksum = 0; icmp_hdr-> id = (USHORT) GetCurrentProcessId (); ICMP_HDR-> SEQ = SEQ_NO; ICMP_HDR-> TimeStamp = GetTickCount (); // "You're dead meat now, packet!" Const unsigned long int deadmeat = 0xDEADBEEF; char * datapart = (char *) icmp_hdr sizeof (ICMPHeader); int bytes_left = packet_size - sizeof (ICMPHeader); while (bytes_left> 0) {memcpy (datapart, & deadmeat, min (int (sizeof (deadmeat)), bytes_left)); bytes_left - = sizeof (deadmeat); datapart = sizeof (deadmeat);} // Calculate a checksum on the result icmp_hdr- > Checksum = ip_checksum ((ushort *) ICMP_HDR, PACKET_SIZE); // Send the generated ICMP package // return value <0 table failed int send_ping (SOCKET sd, const sockaddr_in & dest, ICMPHeader * send_buf, int packet_size) {// Send the ping packet in send_buf as-is cout << "Sending" << packet_size << "bytes to" << inet_ntoa (dest. SIN_ADDR) << "..." << Flush; int bwrote = sendto (SD, (char *) send_buf, packet_size, 0, (sockaddr *) & dest, sizeof (dest)); if (bwrote == Socket_ERROR) { CERR << "Send Failed: << Wsagetlasterror () << endl; return -1;} else if (bwrote Return 0;} // // ICMP packet receiving Returns <0 failed list int recv_ping (SOCKET sd, sockaddr_in & source, IPHeader * recv_buf, int packet_size) {// Wait for the ping reply int fromlen = sizeof (source); int bread = recvfrom ( SD, (char *) Recv_buf, packet_size sizeof (ipheader), 0, (sockaddr *) & source, & fromlen; if (bread == Socket_ERROR) {CERR << "Read Failed:"; if (wsagetlasterror () == Wsaemsgsize) {CERR << "Buffer Too Small" << Endl;} else {cerr << "ERROR #" << Wsagetlasterror () << Endl;} Return -1;} return 0;} / / The ICMP decoding // return value -2 table is ignored, the -1 table failed, 0 success int decode_reply (IpHeader * reply, int Bytes, SockAddr_in * from) {// Skip the IP Baotou, find ICMP Baotou Unsigned short header_len = reply-> h_len * 4; icmpheader * icmphdr = (icmpheader *) ((char *) reply header_len; Rations with the length of the package, Header_len ICMP_MIN is the length IF of the minimum ICMP package (bytes // All work, print information cout << Endl << Bytes << "BYTES from" << inet_ntoa (from> sin_addr) << ", ICMP_SEQ" << ICMphDR-> SEQ << ","; IF ICMPHDR-> type == ICMP_TTL_EXPIRE) {cout << "TTL Expired." << Endl;} else {cout << nhops << "hop" << (NHOPS == 1? ":" s "); cout << ", Time:" << (GettickCount () - ICMPHDR-> TIMESTAMP << "MS." << Endl;} Return 0; Summary and suggestions: ----------- Bugfree suggests that these aspects need to be improved: 1. Header file iostream.h is changed to iostream, the latter is the standard C header to add to std :: cout And std :: endl; Reference to CERR Recommendations to std :: cout (because the latter header file is not supported) 2. The send and acceptance of the program uses synchronous mode, which makes the network problem RECV_PING will fall into continue Waiting. This is what we don't want to see. These three technologies can achieve the purpose: - use multithreading, put the ping package into the thread, process its timeout in the main program - using the select () function to implement WSAAsyncSelect () Here is not specific to these methods, left to the reader to complete. Link: ------- My other article, << dialysis ICMP protocol >>, and other articles see: http://www.9cbs.net/develop/author/netauthor/bugfree/ Contact: ------- zhangliangsd@hotmail.com