#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;
}
socket实现tracert命令(控制台)
最新推荐文章于 2021-05-24 14:22:43 发布