Traceroute(因未知原因未能测试成功,请指教)

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define DEF_ICMP_DATA_SIZE 1024
#define MAX_ICMP_PACKET_SIZE 2048
#include "iostream"
#include "winsock2.h"
#include "string.h"
#include "ws2tcpip.h"
#pragma comment(lib,"WS2_32")
using namespace std;

typedef struct icmp_hdr {
	unsigned char icmp_type;       //icmp包类型
	unsigned char icmp_code;       //代码
	unsigned short icmp_checksum;  //校验和
	unsigned short icmp_id;        //标识
	unsigned short icmp_sequence;  //序列号
	unsigned long icmp_timestamp;  //时间戳
} IcmpHeader;
unsigned short checksum(unsigned short *buff, int size);

int main(int argc, char **argv) {

	//加载winsock2.2
	WSADATA wsaData;
	int ret;
	if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
		cout << "初始化WinSock2.2出错!";
		return -1;
	}

	//输入目的IP地址或域名
	char szDestIp[256] = { 0 };
    cout << "请输入目的地址:" << endl;
	cin.getline(szDestIp, sizeof(szDestIp));
	
	//解析域名
	unsigned long ulDestIP = inet_addr(szDestIp);
	if (ulDestIP == INADDR_NONE) {   //如果不是IP地址
		hostent* pHostent = gethostbyname(szDestIp);
		if (pHostent != NULL) {      //如果是域名,就解析域名  
			ulDestIP = (*(in_addr*)pHostent->h_addr).s_addr;
		}
		else {
			cout << "无法解析主机名" << endl;
			WSACleanup();
			return -1;
		}
	}
	cout << "路由:" << szDestIp << "(" << inet_ntoa(*(in_addr *)(&ulDestIP)) << ")" << endl;

	//创建接收icmp包的原始套接字,绑定到本地端口
	SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);   //收发icmp包的原始套接字
	sockaddr_in in;
	in.sin_family = AF_INET;
	in.sin_port = 0;
	in.sin_addr.S_un.S_addr = INADDR_ANY;
	if (bind(sRaw, (sockaddr *)&in, sizeof(in)) == SOCKET_ERROR) {
		cout << "destination bind failed" << endl;
		WSACleanup();
		return -1;
	}
	int nTime = 10*1000;
	setsockopt(sRaw, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTime, sizeof(nTime));
	
	//构造icmp包
	char IcmpSendBuf[sizeof(IcmpHeader) + DEF_ICMP_DATA_SIZE];
	char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE];
	memset(IcmpSendBuf, 0, sizeof(0));
	memset(IcmpRecvBuf, 0, sizeof(0));

	//填充icmp包
	IcmpHeader *pIcmp = (IcmpHeader *)IcmpSendBuf;
	pIcmp->icmp_type = 8;      //回显请求
	pIcmp->icmp_code = 0;
	pIcmp->icmp_id = (unsigned short)GetCurrentProcessId();
	memset(IcmpSendBuf + sizeof(IcmpHeader), 'E', DEF_ICMP_DATA_SIZE);   //填充数据部分
	
	//填充发送目的地址
	sockaddr_in destAddr;
	destAddr.sin_family = AF_INET;
	destAddr.sin_port = htons(22);
	destAddr.sin_addr.S_un.S_addr = ulDestIP;
	int nRet, nTick, nTTL = 1, iSeqNo = 0;

	//发送报文并接收路由器的差错报告报文
	IcmpHeader *pICMPHdr;       //指向报文首部的指针
	char *szIP;
	SOCKADDR_IN recvAddr;
	int n, nLen = sizeof(recvAddr);
	do {
		setsockopt(sRaw, IPPROTO_IP, IP_TTL, (char *)&nTTL, sizeof(nTTL));
		nTick = GetTickCount();

		//填写序列号,计算校验和
		((IcmpHeader *)IcmpSendBuf)->icmp_checksum = 0;
		((IcmpHeader *)IcmpSendBuf)->icmp_sequence = htons(iSeqNo++);
		((IcmpHeader *)IcmpSendBuf)->icmp_checksum = checksum((unsigned short*)IcmpSendBuf, sizeof(IcmpHeader) + DEF_ICMP_DATA_SIZE);
		
		nRet = sendto(sRaw, IcmpSendBuf, sizeof(IcmpSendBuf), 0, (sockaddr *)&destAddr, sizeof(destAddr));
		if (nRet == SOCKET_ERROR) {
			cout << "send failed!" << endl;
			break;
		}
		n = 0;
		do {
			n++;
			//cout << n << endl;
			nRet = recvfrom(sRaw, IcmpRecvBuf, sizeof(IcmpRecvBuf), 0, (sockaddr *)&recvAddr, &nLen);
			//cout << sRaw << endl;

			if (nRet == SOCKET_ERROR) {
				cout << "receive failed! 错误码:" << WSAGetLastError() << endl;
				closesocket(sRaw);
				WSACleanup();
				return -1;
			}
			pICMPHdr = (IcmpHeader *)&IcmpRecvBuf[20];
			szIP = inet_ntoa(recvAddr.sin_addr);
			if (pICMPHdr->icmp_type == 11 || pICMPHdr->icmp_type == 0 || pICMPHdr->icmp_type == 3)
				break;
		} while (n < 10);

		if (n > 10)continue;
		cout << nTTL << " 地址:" << szIP << " 用时" << GetTickCount() - nTick << " ms" << endl;
		if (pICMPHdr->icmp_type == 3) {
			switch (pICMPHdr->icmp_code) {
			   case 0:cout << "目的网络不可达!" << endl; break;
			   case 1:cout << "目的主机不可达!" << endl; break;
			   case 6:cout << "未知目的网络!" << endl; break;
			   case 7:cout << "未知目的主机!" << endl; break;
			}
			break;
		}
		if (destAddr.sin_addr.S_un.S_addr == recvAddr.sin_addr.S_un.S_addr) {
			cout << "目标可达." << endl;
			break;
		}
	} while (nTTL++ < 30);
	closesocket(sRaw);
	WSACleanup();
	return 0;
}

unsigned short checksum(unsigned short * buff, int size) {
	unsigned long cksum = 0;
	while (size > 1) {
		cksum += *buff++;
		size -= sizeof(unsigned short);
	}
	if (size)cksum += *(char *)buff;
	cksum = (cksum >> 16) + (cksum & 0xffff);
	cksum += (cksum >> 16);
	return (unsigned short)(~cksum);
}

实际上如果输入我家路由器的IP可以追踪到,但是输入www.baidu.com或者其ip地址就追踪不到(receive不到消息)。原因不明。程序貌似没错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值