La realización del programa ping de programación de red de windowsw

[Propósito experimental]
1. Familiarizarse con el proceso básico de programación de sockets originales
2. Comprender el mecanismo de implementación del programa ping
3. Comprender la función y el formato de mensaje del protocolo ICMP.
4. Complete la configuración del enchufe original.

[Contenido experimental]
1. Construya la estructura del encabezado del protocolo ICMP
2. Construya la estructura de la solicitud de eco ICMP.
3. Construir una estructura de respuesta retrorreflectante ICMP.
4. Construya la estructura del encabezado IP.
5. Cree un socket sin formato.
6. Obtenga la IP de destino de acuerdo con la dirección especificada por el usuario.
7. Envío cíclico de solicitudes ICMP a la dirección de destino.
8. Espere la respuesta de la otra parte y calcule el intervalo de tiempo.

Código fuente:
ping.h

#pragma pack(1)

#define ICMP_ECHOREPLY	0
#define ICMP_ECHOREQ	8

// IP Header -- RFC 791
typedef struct tagIPHDR
{
    
    
	u_char  VIHL;			// Version and IHL
	u_char	TOS;			// Type Of Service
	short	TotLen;			// Total Length
	short	ID;				// Identification
	short	FlagOff;		// Flags and Fragment Offset
	u_char	TTL;			// Time To Live
	u_char	Protocol;		// Protocol
	u_short	Checksum;		// Checksum
	struct	in_addr iaSrc;	// Internet Address - Source
	struct	in_addr iaDst;	// Internet Address - Destination
}IPHDR, * PIPHDR;


// ICMP Header - RFC 792
typedef struct tagICMPHDR
{
    
    
	u_char	Type;			// Type
	u_char	Code;			// Code
	u_short	Checksum;		// Checksum
	u_short	ID;				// Identification
	u_short	Seq;			// Sequence
	char	Data;			// Data
}ICMPHDR, * PICMPHDR;


#define REQ_DATASIZE 32		// Echo Request Data size

// ICMP Echo Request
typedef struct tagECHOREQUEST
{
    
    
	ICMPHDR icmpHdr;
	DWORD	dwTime;
	char	cData[REQ_DATASIZE];
}ECHOREQUEST, * PECHOREQUEST;


// ICMP Echo Reply
typedef struct tagECHOREPLY
{
    
    
	IPHDR	ipHdr;
	ECHOREQUEST	echoRequest;
	char    cFiller[256];
}ECHOREPLY, * PECHOREPLY;

#pragma pack()

ping.c

//
// PING.C -- Ping program using ICMP and RAW Sockets
//
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
//#include <winsock.h>
#include <WinSock2.h>
#pragma comment (lib,"Ws2_32.lib")
#include "ping.h"

// Internal Functions
void Ping(LPCSTR pstrHost);
void ReportError(LPCSTR pstrFrom);
int  WaitForEchoReply(SOCKET s);
u_short in_cksum(u_short* addr, int len);

// ICMP Echo Request/Reply functions
int		SendEchoRequest(SOCKET, LPSOCKADDR_IN);
DWORD	RecvEchoReply(SOCKET, LPSOCKADDR_IN, u_char*);


// main()
void main(int argc, char** argv)
{
    
    
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(1, 1);
	int nRet;

	// Check arguments
	if (argc != 2)
	{
    
    
		fprintf(stderr, "\nUsage: ping hostname\n");
		return;
	}

	// Init WinSock
	nRet = WSAStartup(wVersionRequested, &wsaData);
	if (nRet)
	{
    
    
		fprintf(stderr, "\nError initializing WinSock\n");
		return;
	}

	// Check version
	if (wsaData.wVersion != wVersionRequested)
	{
    
    
		fprintf(stderr, "\nWinSock version not supported\n");
		return;
	}

	// Go do the ping
	Ping(argv[1]);

	// Free WinSock
	WSACleanup();
}


// Ping()
// Calls SendEchoRequest() and
// RecvEchoReply() and prints results
void Ping(LPCSTR pstrHost)
{
    
    
	SOCKET	  rawSocket;
	LPHOSTENT lpHost;
	struct    sockaddr_in saDest;
	struct    sockaddr_in saSrc;
	DWORD	  dwTimeSent;
	DWORD	  dwElapsed;
	u_char    cTTL;
	int       nLoop;
	int       nRet;

	// Create a Raw socket
	rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if (rawSocket == SOCKET_ERROR)
	{
    
    
		ReportError("socket()");
		return;
	}

	// Lookup host
	lpHost = gethostbyname(pstrHost);
	if (lpHost == NULL)
	{
    
    
		fprintf(stderr, "\nHost not found: %s\n", pstrHost);
		return;
	}

	// Setup destination socket address
	saDest.sin_addr.s_addr = *((u_long FAR*) (lpHost->h_addr));
	saDest.sin_family = AF_INET;
	saDest.sin_port = 0;

	// Tell the user what we're doing
	printf("\nPinging %s [%s] with %d bytes of data:\n",
		pstrHost,
		inet_ntoa(saDest.sin_addr),
		REQ_DATASIZE);

	// Ping multiple times
	for (nLoop = 0; nLoop < 4; nLoop++)
	{
    
    
		// Send ICMP echo request
		SendEchoRequest(rawSocket, &saDest);

		// Use select() to wait for data to be received
		nRet = WaitForEchoReply(rawSocket);
		if (nRet == SOCKET_ERROR)
		{
    
    
			ReportError("select()");
			break;
		}
		if (!nRet)
		{
    
    
			printf("\nTimeOut");
			break;
		}

		// Receive reply
		dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);

		// Calculate elapsed time
		dwElapsed = GetTickCount() - dwTimeSent;
		printf("\nReply from: %s: bytes=%d time=%ldms TTL=%d",
			inet_ntoa(saSrc.sin_addr),
			REQ_DATASIZE,
			dwElapsed,
			cTTL);
	}
	printf("\n");
	nRet = closesocket(rawSocket);
	if (nRet == SOCKET_ERROR)
		ReportError("closesocket()");
}


// SendEchoRequest()
// Fill in echo request header
// and send to destination
int SendEchoRequest(SOCKET s, LPSOCKADDR_IN lpstToAddr)
{
    
    
	static ECHOREQUEST echoReq;
	static nId = 1;
	static nSeq = 1;
	int nRet;

	// Fill in echo request
	echoReq.icmpHdr.Type = ICMP_ECHOREQ;
	echoReq.icmpHdr.Code = 0;
	echoReq.icmpHdr.Checksum = 0;
	echoReq.icmpHdr.ID = nId++;
	echoReq.icmpHdr.Seq = nSeq++;

	// Fill in some data to send
	for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
		echoReq.cData[nRet] = ' ' + nRet;

	// Save tick count when sent
	echoReq.dwTime = GetTickCount();

	// Put data in packet and compute checksum
	echoReq.icmpHdr.Checksum = in_cksum((u_short*)& echoReq, sizeof(ECHOREQUEST));

	// Send the echo request  								  
	nRet = sendto(s,						/* socket */
		(LPSTR)& echoReq,			/* buffer */
		sizeof(ECHOREQUEST),
		0,							/* flags */
		(LPSOCKADDR)lpstToAddr, /* destination */
		sizeof(SOCKADDR_IN));   /* address length */

	if (nRet == SOCKET_ERROR)
		ReportError("sendto()");
	return (nRet);
}


// RecvEchoReply()
// Receive incoming data
// and parse out fields
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char* pTTL)
{
    
    
	ECHOREPLY echoReply;
	int nRet;
	int nAddrLen = sizeof(struct sockaddr_in);

	// Receive the echo reply	
	nRet = recvfrom(s,					// socket
		(LPSTR)& echoReply,	// buffer
		sizeof(ECHOREPLY),	// size of buffer
		0,					// flags
		(LPSOCKADDR)lpsaFrom,	// From address
		&nAddrLen);			// pointer to address len

// Check return value
	if (nRet == SOCKET_ERROR)
		ReportError("recvfrom()");

	// return time sent and IP TTL
	*pTTL = echoReply.ipHdr.TTL;
	return(echoReply.echoRequest.dwTime);
}

// What happened?
void ReportError(LPCSTR pWhere)
{
    
    
	fprintf(stderr, "\n%s error: %d\n",
		WSAGetLastError());
}


// WaitForEchoReply()
// Use select() to determine when
// data is waiting to be read
int WaitForEchoReply(SOCKET s)
{
    
    
	struct timeval Timeout;
	fd_set readfds;

	readfds.fd_count = 1;
	readfds.fd_array[0] = s;
	Timeout.tv_sec = 5;
	Timeout.tv_usec = 0;

	return(select(1, &readfds, NULL, NULL, &Timeout));
}


//
// Mike Muuss' in_cksum() function
// and his comments from the original
// ping program
//
// * Author -
// *	Mike Muuss
// *	U. S. Army Ballistic Research Laboratory
// *	December, 1983

/*
 *			I N _ C K S U M
 *
 * Checksum routine for Internet Protocol family headers (C Version)
 *
 */
u_short in_cksum(u_short* addr, int len)
{
    
    
	register int nleft = len;
	register u_short* w = addr;
	register u_short answer;
	register int sum = 0;

	/*
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
	 *  we add sequential 16 bit words to it, and at the end, fold
	 *  back all the carry bits from the top 16 bits into the lower
	 *  16 bits.
	 */
	while (nleft > 1) {
    
    
		sum += *w++;
		nleft -= 2;
	}

	/* mop up an odd byte, if necessary */
	if (nleft == 1) {
    
    
		u_short	u = 0;

		*(u_char*)(&u) = *(u_char*)w;
		sum += u;
	}

	/*
	 * add back carry outs from top 16 bits to low 16 bits
	 */
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
	sum += (sum >> 16);			/* add carry */
	answer = ~sum;				/* truncate to 16 bits */
	return (answer);
}


Cambiar la información de depuración de ping
Inserte la descripción de la imagen aquí
Efecto de la operación:
Inserte la descripción de la imagen aquí
Captura de pantalla del efecto de captura de paquetes icmp:
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/Gunanhuai/article/details/109815129
Recomendado
Clasificación