socket实现tracert命令(控制台)

#include <winsock2.h>
#include <iostream>
#include <windows.h>
using namespace std;

#define DATA_SIZE 32			//icmp包数据大小
#define RECV_MAX_SZIE 1024		//接收的数据最大长度
#define IP_TTL 4				//optname
#define MAX_HOP 30				//最大跃点数
#pragma comment(lib, "ws2_32.lib")

typedef struct tag_icmphdr		//icmp头
{
	unsigned char	icmp_type;
	unsigned char	icmp_code;	
	unsigned short	icmp_checksum;
	unsigned short	icmp_id;
	unsigned short	icmp_sequence;
	unsigned long	icmp_timestamp;
} ICMPHDR, *PICMPHDR;

typedef struct tag_iphdr
{
	unsigned char	ip_verlen; 
	unsigned char	ip_tos; 
	unsigned short	ip_totallength; 
	unsigned short	ip_id; 
	unsigned short	ip_offset; 
	unsigned char	ip_ttl; 
	unsigned char	ip_protocol; 
	unsigned short	ip_checksum; 
	unsigned int	ip_srcaddr; 
	unsigned int	ip_destaddr; 
} IPHDR, *PIPHDR;

void FillIcmp(char *icmp)
{
	PICMPHDR p = (PICMPHDR)icmp;
	p->icmp_type = 8;
	p->icmp_code = 0;
	p->icmp_checksum = 0;
	p->icmp_id = (unsigned short)::GetCurrentProcessId();
	p->icmp_sequence = 0;
	p->icmp_timestamp = 0;
}

USHORT CheckSum(USHORT *buf,int size)
{
	USHORT cksum=0;
	while(size>1)
	{
		cksum+=*buf++;
		size-=sizeof(USHORT);
	}
	if(size)
		cksum+=*buf++;
	cksum=(cksum>>16)+(cksum&0xffff);
	cksum+=(cksum>>16);
	return (USHORT)(~cksum);
}

int g_size = sizeof(ICMPHDR)+DATA_SIZE;

int _tmain(int argc, _TCHAR* argv[])
{
	WORD version = MAKEWORD(2,2);
	WSADATA data;
	WSAStartup(version, &data);
	if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
	{
		cout << "WSAStartup failed" << endl;
		WSACleanup();
		return 0;
	}

	char ip[20];
	cout << "tracert:";
	cin >> ip;

	cout << endl << "Tracing route to" << ip << "[" << ip << "]" << "with a maximum of 30 hops." << endl << endl;

	SOCKADDR_IN addr;															
	addr.sin_family = AF_INET;
	addr.sin_addr.S_un.S_addr = inet_addr(ip);
	addr.sin_port = htons(0);

	SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);						     //创建原始套接字

	int bOpt = 1;
	int outTime = 2000;
	int rst;

	rst = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&outTime, sizeof(int));	//设置发送超时
	if (SOCKET_ERROR == rst)
	{
		cout << "setsockopt erro" << endl;
		closesocket(sock);
		WSACleanup();
		return -1;
	}

	rst = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&outTime, sizeof(int));	//设置接收超时
	if (SOCKET_ERROR == rst)
	{
		cout << "setsockopt erro" << endl;
		closesocket(sock);
		WSACleanup();
		return -1;
	}


	char *icmp = (char*)malloc(g_size);						//为icmp包申请内存
	memset(icmp, 0, g_size);								//内存空间置零
	FillIcmp(icmp);											//填充icmp包

	unsigned short sequence = 0;							//序列号
	int count = 4;											//发送请求次数
	char recvbuf[RECV_MAX_SZIE];							//接收buf
	SOCKADDR_IN addrfrom;									//接收地址
	int len = sizeof(SOCKADDR);								//地址大小	
	int ttl = 1;											//TTL
	int result;

	while (1)
	{
		result = setsockopt(sock, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(int));
		if (SOCKET_ERROR == result)
		{
			cout << "setsockopt IP_TTL error" << endl;
			closesocket(sock);
			WSACleanup();
			return -1;
		}

		
		((PICMPHDR)icmp)->icmp_checksum = 0;
		((PICMPHDR)icmp)->icmp_checksum = CheckSum((USHORT*)icmp, g_size);

		int nTickPre = ::GetTickCount();
		result = sendto(sock, icmp, g_size, 0, (SOCKADDR*)&addr, sizeof(SOCKADDR));	//向目标主机发送icmp请求包
		if (SOCKET_ERROR == result)
		{
			if (WSAETIMEDOUT == WSAGetLastError())
			{
				cout << "time out" << endl;
				continue;
			}
			else
			{
				cout << "sendto error" << endl;
				closesocket(sock);
				WSACleanup();
				return -1;
			}
		}

		result = recvfrom(sock, recvbuf, RECV_MAX_SZIE, 0, (SOCKADDR*)&addrfrom, &len);	//接收路由器返回的“icmp超时”报文(ttl等于0)
		if (SOCKET_ERROR == result)
		{
			if (WSAETIMEDOUT == GetLastError())
			{
				cout << ttl << ":	"  << "*	"<< "time out" << endl;
				++ttl;
				continue;
			}
			else
			{
				cout << "recvform error" << endl;
				closesocket(sock);
				WSACleanup();
				return -1;
			}
		}

		int nTickNow = ::GetTickCount();
		int time = nTickNow - nTickPre;

		PIPHDR pip = (PIPHDR)recvbuf;
		char sip[20];
		in_addr srcaddr;
		srcaddr.S_un.S_addr = pip->ip_srcaddr;
		strcpy(sip, inet_ntoa(srcaddr));
		if (time == 0)
			cout << ttl << ":	"  <<  "<1ms	"<< sip << endl;
		else
			cout << ttl << ":	"  << time << "ms	"<< sip << endl;

		if (strcmp(ip, sip) == 0)
		{
			cout << "tracert complete" << endl;
			break;
		}

		++ttl;

		if (ttl > 30)
		{
			break;
		}
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/cbuttonst/article/details/7624575