📄 iroute.cpp
字号:
#include<iostream.h>
#include<winsock2.h>
#include<ws2tcpip.h>
#include<iomanip.h>
//定义ip头部结构体
typedef struct iphdr{
unsigned int headlen:4; //4位IP头长度
unsigned int version:4; //4位IP版本号
unsigned char tos; //服务类型
unsigned short totallen; //IP包总长度
unsigned short id; //ID号
unsigned short flag; //标记
unsigned char ttl; //生存时间
unsigned char prot; //协议
unsigned short checksum; //校验和
unsigned int sourceIP; //源IP
unsigned int destIP; //目的IP
}IpHeader;
typedef struct icmphdr{
BYTE type; //ICMP类型码,回送请求的类型码为8
BYTE code; //子类型码,保存与特定ICMP报文类型相关的细节信息
USHORT checksum; //校验和
USHORT id; //ICMP报文ID号
USHORT seq; //ICMP数据报的序列号
}IcmpHeader;
#define ICMP_ECHO 8 //请求回送
#define ICMP_ECHO_REPLY 0 //请求回应
#define ICMP_MIN 8 //ICMP包头长度(最小ICMP包长度)
#define STATUS_FAILED 0xFFFF //错误码
#define DEF_PACKET_SIZE 32 //缺省数据报长度
#define MAX_PACKET 1024 //最大数据块长度
#define MAX_PACKET_SIZE (MAX_PACKET+sizeof(IpHeader)) //最大接收数据包长度
void fill_icmp_data(char*,int); //填充ICMP包
USHORT checksum(USHORT*,int); //校验和函数
void main(int argc,char*argv[])
{
if(argc!=2)
{
cout<<"Input Error!"
<<endl
<<"Please input:iroute dest_ip"
<<endl;
exit(0);
}
cout<<endl<<"Tracing route to "<<argv[1]<<" over a maximum of 30 hops"<<endl<<endl;
WSADATA wsaData;
if(WSAStartup(0x102,&wsaData)!=0) //开始使用Ws2_32.dll
{
cout<<"WSAStartup failed:"<<GetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
//创建原始套接字
SOCKET sock;
sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);
if(sock==INVALID_SOCKET)
{
cout<<"WSASocket() failed:"<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
//设置接收延时
int timeout=1000;
int bread=setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout));
if(bread==SOCKET_ERROR)
{
cout<<"failed to set recv timeout:"<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
//设置发送延时
timeout=1000;
bread=setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));
if(bread==SOCKET_ERROR)
{
cout<<"failed to set send timeout:"<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
struct sockaddr_in dest,from; //dest:目的IP,from:接收ICMP包的源IP
int fromlen=sizeof(from); //接收ICMP包长度
char* recvbuf=new char[MAX_PACKET_SIZE];//接收ICMP包缓冲区
memset(&dest,0,sizeof(dest)); //初始化dest结构
dest.sin_family=AF_INET;
dest.sin_addr.s_addr=inet_addr(argv[1]); //填入目的IP地址
char icmp_data[MAX_PACKET]; //MAX_PACKET是数据报最大可能的长度
memset(icmp_data,0,MAX_PACKET); //将数据报清空初始化
int datasize=DEF_PACKET_SIZE; //数据报报文体的缺省长度
datasize+=sizeof(IcmpHeader); //加上报头的长度
fill_icmp_data(icmp_data,datasize); //填充ICMP数据报
((IcmpHeader*)icmp_data)->checksum=0; //先将校验和置零
((IcmpHeader*)icmp_data)->seq=0; //序列号设为0
//计算校验和后填入
((IcmpHeader*)icmp_data)->checksum=checksum((USHORT*)icmp_data,datasize);
int ttl=1; //ttl初始值为1
//开始路由,当找到目的主机或达到30跳时退出
while(from.sin_addr.s_addr!=dest.sin_addr.s_addr&&ttl<=30)
{
//设置IP报头的TTL
bread=setsockopt(sock,IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl));
if(bread==SOCKET_ERROR)
{
cout<<"failed to set IP_TTL:"<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
}
unsigned long tc = GetTickCount(); //发送时间
//发送数据报
bread=sendto(sock,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));
int n=0;
if(bread==SOCKET_ERROR)
{
if(WSAGetLastError()==WSAETIMEDOUT)
{
cout<<"Request timed out"<<endl;
}
cout<<endl<<"Sendto failed:"<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
n=1;
}
if(WSAGetLastError()==WSAETIMEDOUT)
{
cout<<"Request timed out"<<endl;
ExitProcess(STATUS_FAILED);
n=1;
}
if(bread<datasize)
{
cout<<"Wrote "<<bread<<" bytes"<<endl;
ExitProcess(STATUS_FAILED);
n=1;
}
//接收数据报
bread=recvfrom(sock,recvbuf,MAX_PACKET_SIZE,0,(struct sockaddr*)&from,&fromlen);
if(bread==SOCKET_ERROR)
{
if(WSAGetLastError()==WSAETIMEDOUT)
{
cout<<setw(3)<<ttl<<" Request timed out"<<endl;
}
cout<<endl<<"Receive failed:"<<WSAGetLastError()<<endl;
ExitProcess(STATUS_FAILED);
n=1;
}
unsigned int ms=GetTickCount()-tc; //计算总时间
//去掉IP报头,输出IP地址
if(n==0)
{
IpHeader* iphdr;
IcmpHeader* icmphdr;
unsigned short iphdrlen;
iphdr=(IpHeader*)recvbuf;
iphdrlen=iphdr->headlen*4; //IP报头的长度
icmphdr=(IcmpHeader*)(recvbuf+iphdrlen); //跳过IP报头
if(bread<iphdrlen+ICMP_MIN) continue; //数据报太短,丢弃
//输出相关信息
cout<<setw(3)<<ttl;
if(ms<1)
cout<<setw(4)<<"<1"<<" ms ";
else
cout<<setw(4)<<ms<<" ms ";
cout<<inet_ntoa(from.sin_addr)<<endl;
ttl++;
}
}
cout<<endl<<"Trace complete"<<endl;
}
//填充ICMP包
void fill_icmp_data(char*icmp_data,int datasize)
{
IcmpHeader* icmp_hdr;
char *datapart;
icmp_hdr=(IcmpHeader*)icmp_data;
icmp_hdr->type=ICMP_ECHO;
icmp_hdr->id=(USHORT)GetCurrentThreadId();
datapart=icmp_data+sizeof(IcmpHeader);
memset(datapart,'A',datasize-sizeof(IcmpHeader));
}
//计算校验和
USHORT checksum(USHORT *buffer,int size)
{
unsigned long cksum=0;
while(size>1)
{
cksum+=*buffer++;
size-=sizeof(USHORT);
}
if(size)
{
cksum+=*(UCHAR*)buffer;
}
cksum=(cksum>>16)+(cksum& 0xffff);
cksum+=cksum>>16;
return(USHORT)(~cksum);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -