用icmp实现traceroute功能 到最后一跳接收超时是什么问题?
用icmp实现traceroute功能 到最后一跳接收超时是什么问题?
int m_nTimeout = 1000;
BOOL m_bDone=FALSE;
int m_nDatasize;
int m_nMaxhops=30;
//初始化 socket
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData) !=0){
printf("WSAStartup failed!\n");
return 1;
}
//创建socket
m_sockRaw = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,
0,WSA_FLAG_OVERLAPPED);
if(m_sockRaw == INVALID_SOCKET){
printf("WSASocket failed!\n");
return -1;
}
//设置发送和接收超时参数
int ret = setsockopt(m_sockRaw,SOL_SOCKET,SO_RCVTIMEO,
(char *)&m_nTimeout,sizeof(m_nTimeout));
if(ret == SOCKET_ERROR){
printf("设置接收超时参数失败!\n");
return -1;
}
ret = setsockopt(m_sockRaw,SOL_SOCKET,SO_SNDTIMEO,
(char*)&m_nTimeout,sizeof(m_nTimeout));
if(ret == SOCKET_ERROR){
printf("设置发送超时参数失败!\n");
return -1;
}
//解析地址
char strHost[]="202.114.18.190";
//printf("1111111111111111111111111111111111111111111111111");
m_addrDest.sin_family = AF_INET;
if((m_addrDest.sin_addr.s_addr=inet_addr(strHost))==INADDR_NONE){
HOSTENT * hp;
hp=gethostbyname(strHost);
if(hp)
memcpy(&(m_addrDest.sin_addr),hp->h_addr,hp->h_length);
else{
printf("输入的主机不存在!\n");
return 1;
}
}
////设置路由选项
int bOpt = TRUE;
if(setsockopt(m_sockRaw,SOL_SOCKET,SO_DONTROUTE,(char *)&bOpt,
sizeof(BOOL))==SOCKET_ERROR){
printf("设置socket参数失败!\n");
return 1;
}
m_nDatasize = DEF_PACKET_SIZE;
m_nDatasize+=sizeof(IcmpHeader);
//为icmp 数据包分配发送和接收缓冲区
m_IcmpData = (char *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);
m_RcvBuffer = (char *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);
if((!m_IcmpData)|(!m_RcvBuffer)){
printf("堆分配数据失败!\n");
return 1;
}
//创建icmp数据包
memset(m_IcmpData,0,MAX_PACKET);
printf("Tracing route to %s over a maximum of %d hops:\r\n",strHost,m_nMaxhops);
////fill_icmp_data(m_IcmpData,m_nDatasize);//////
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader*)m_IcmpData;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
icmp_hdr->i_cksum=0;
icmp_hdr->i_seq = 0;
datapart = m_IcmpData+sizeof(IcmpHeader);
memset(datapart,'E',m_nDatasize-sizeof(IcmpHeader));
////////////////////////////////////
for(m_nTTL =1;((m_nTTL<=m_nMaxhops)&&(!m_bDone));m_nTTL++)
{
int bwrote;
//设置socket生命周期
//set_ttl(m_sockRaw,m_nTTL);/////////////////////
if((setsockopt(m_sockRaw,IPPROTO_IP,IP_TTL,(LPSTR)&m_nTTL,sizeof(int)))==SOCKET_ERROR)
{
printf("设置socket选项失败!");
return 0;
}
//往icmp头部添加信息
((IcmpHeader*)m_IcmpData)->i_cksum = 0;
((IcmpHeader*)m_IcmpData)->timestamp=GetTickCount();
((IcmpHeader*)m_IcmpData)->i_seq=m_nSeqno++;
((IcmpHeader*)m_IcmpData)->i_cksum=checksum((USHORT*)m_IcmpData,
m_nDatasize);
//发送icmp包到目的端
bwrote = sendto(m_sockRaw,m_IcmpData,m_nDatasize,0,
(SOCKADDR*)&m_addrDest,sizeof(m_addrDest));
if(bwrote == SOCKET_ERROR)
{
if(WSAGetLastError()==WSAETIMEDOUT){
printf("%2d Send request timed out ./t/n",m_nTTL);
continue ;
}
printf("发送数据函数出错!\r\n");
}
//从目的端读取数据报
int fromlen;
fromlen = sizeof(SOCKADDR);
ret = recvfrom(m_sockRaw,m_RcvBuffer,MAX_PACKET,0,(struct sockaddr*)&m_addrFrom,&fromlen);
if(ret == SOCKET_ERROR)
{
if(WSAGetLastError()==WSAETIMEDOUT){
printf("%2d Recvive request timed out .\t\n",m_nTTL);
continue ;
}
printf("接受数据函数出错!\r\n");
return -1;
}
//解析返回的icmp数据报的信息
m_bDone = decode_resp(m_RcvBuffer,ret,&m_addrFrom,m_nTTL);//////////////////
Sleep(1000);
}
getchar();
}
void fill_icmp_data(char * icmp_data,int datasize){
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader*)icmp_data;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
icmp_hdr->i_seq = 0;
datapart = icmp_data+sizeof(IcmpHeader);
memset(datapart,'E',datasize-sizeof(IcmpHeader));
}
/*int set_ttl(SOCKET s,int nTimeToLive){
int nRet;
nRet = setsockopt(s,IPPROTO_IP,IP_TTL,(LPSTR)&nTimeToLive,
sizeof(int));
if(nRet == SOCKET_ERROR){
printf("设置socket选项失败!\n");
return 0 ;
}
return 1;
}*/
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);
}
int decode_resp(char *buf,int bytes,SOCKADDR_IN* from,int ttl)
{
IpHeader *iphdr = NULL;
IcmpHeader *icmphdr = NULL;
unsigned short iphdrlen;
struct hostent *IpHostent = NULL;
struct in_addr inaddr = from->sin_addr;
iphdr = (IpHeader*)buf;
iphdrlen = iphdr->h_len*4;
if(bytes<iphdrlen+ICMP_MIN){
printf("Too few bytes from %s\n",from->sin_addr);
}
icmphdr = (IcmpHeader*)(buf+iphdrlen);
switch(icmphdr->i_type){
case ICMP_ECHOREPLY://目的地址返回的icmp
IpHostent = gethostbyaddr((const char*)&from->sin_addr,
AF_INET,sizeof(struct in_addr));
if(IpHostent!=NULL)
printf("%2d %s(%s)\r\n",ttl,IpHostent->h_name,inet_ntoa(inaddr));
return 1;break;
case ICMP_TIMEOUT://沿着这条链路返回的路由
printf("%2d %s\r\n",ttl,inet_ntoa(inaddr));
return 0;break;
case ICMP_DESTUNREACH://不能够到达目的的地址
printf("%2d %s reports:HOST is unreachable \r\n",ttl,inet_ntoa(inaddr));
return 1;
break;
default:
printf("non-echo type%d recvd\n",icmphdr->i_type);
return 1;
break;
}
return 0;
}
[解决办法]
有可能对方有firewall,不回应icmp.这里也有traceroute调试好的程序,你可以参考:
http://download.csdn.net/detail/geoff08zhang/4571358
[解决办法]
用tracert命令能跳到最后 应该是程序的问题