
![]() 图1 ICMP时间戳请求和应答报文 一般时间戳程序返回三个值,分别是发起时间戳(orig)、接收时间戳(recv)和发送时间戳(xmit)。但一般情况下,应答机器都将接收时间戳和发送时间戳设为同一个值。 |
| #define ICMP_SEND 13 // 时间戳请求 #define ICMP_REPLY 14 // 时间戳回答 #define ICMP_MIN 12 // ICMP的头字节最小在得低于12个字节 #define STATUS_FAILED 0xFFFF #define MAX_PACKET 1024 #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s)) #define xfree(p) HeapFree(GetProcessHeap(),0,(p)) |
| /* IP 头结构,共20个字节 */ typedef struct iphdr { unsigned char h_len:4; // 头长度 unsigned char version:4; // IP版本 unsigned char tos; // 服务类型 unsigned short total_len; // IP包的问长度 unsigned short ident; // 唯一标识 unsigned short frag_and_flags; // 标志 unsigned char ttl; // 往返时间 unsigned char proto; // 传输的协议(如TCP、UDP等) unsigned short checksum; // IP校验和 unsigned int sourceIP; // 源地址 unsigned int destIP; // 目标地址 } IpHeader; /* ICMP头结构, 12个字节 */ typedef struct _ihdr { BYTE i_type; BYTE i_code; USHORT i_cksum; USHORT i_id; USHORT i_seq; ULONG origtimestamp; //发起时间戳 ULONG recvtimestamp; //接收时间戳 ULONG xmittimestamp; //发送时间戳 } IcmpHeader; |
| void fill_icmp_head(char * icmp_data) { IcmpHeader *icmp_hdr; icmp_hdr = (IcmpHeader*)icmp_data; icmp_hdr->i_type = ICMP_SEND; // 发送请求 icmp_hdr->i_code = 0; icmp_hdr->i_cksum = 0; icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); icmp_hdr->i_seq = 0; } |
| USHORT checksum(USHORT *buffer, int size) { unsigned long cksum=0; // 初始化校验和为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); } |
| void decode_resp(char *buf, int bytes,struct sockaddr_in *from) { IpHeader *iphdr; IcmpHeader *icmphdr; unsigned short iphdrlen; iphdr = (IpHeader *)buf; iphdrlen = iphdr->h_len * 4 ; // 32位相当于4个字节 if (bytes < iphdrlen + ICMP_MIN) { printf("字节太少了 %s\n",inet_ntoa(from->sin_addr)); } icmphdr = (IcmpHeader*)(buf + iphdrlen); if (icmphdr->i_type != ICMP_REPLY) { fprintf(stderr,"没有这个类型 %d recvd\n",icmphdr->i_type); return; } if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) { fprintf(stderr,"错误!\n"); return ; } printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr)); printf(" icmp_seq = %d. ",icmphdr->i_seq); printf(" orig: %d ms, recv: %d ms, xmit: %d ms ",icmphdr->origtimestamp, icmphdr->recvtimestamp, icmphdr->xmittimestamp); printf("\n"); } |
| int main(int argc, char* argv[]) { WSADATA wsaData; SOCKET sockRaw; struct sockaddr_in dest,from; struct hostent *hp; int bread,datasize; int fromlen = sizeof(from); char *dest_ip; char *icmp_data; char *recVBuf; unsigned int addr=0; USHORT seq_no = 0; // 选择Socket版本 if (WSAStartup(0x0101,&wsaData) != 0) { fprintf(stderr,"WSAStartup失败: %d\n",GetLastError()); ExitProcess(STATUS_FAILED); } if (argc <2 ) { Usage(argv[0]); } if((sockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))==INVALID_SOCKE) { fprintf(stderr,"WSAStartup 失败: %d\n",GetLastError()); ExitProcess(STATUS_FAILED); } memset(&dest,0,sizeof(dest)); hp = gethostbyname(argv[1]); // 从参数中得到目标机器的IP if (hp!=NULL) { memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); dest.sin_family = AF_INET; dest_ip = inet_ntoa(dest.sin_addr); } else { fprintf(stderr,"IP地址不能为空 %s\n",argv[1]); ExitProcess(STATUS_FAILED); } datasize=sizeof(IcmpHeader); icmp_data = xmalloc(MAX_PACKET); recvbuf = xmalloc(MAX_PACKET); if (!icmp_data) { fprintf(stderr,"分配内存空间失败! %d\n",GetLastError()); ExitProcess(STATUS_FAILED); } memset(icmp_data,0,MAX_PACKET); fill_icmp_head(icmp_data); while(1) // 开始执行循环发送ICMP报文部分 { int bwrote; ((IcmpHeader*)icmp_data)->i_cksum = 0; ((IcmpHeader*)icmp_data)->origtimestamp = GetTickCount(); ((IcmpHeader*)icmp_data)->i_seq = seq_no++; ((IcmpHeader*)icmp_data)->i_cksum=checksum((USHORT*)icmp_data,sizeof(IcmpHeader)); // 开始向目标机器发送ICMP报文 bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest)); if (bwrote == SOCKET_ERROR) { fprintf(stderr,"sendto 失败: %d\n",WSAGetLastError()); ExitProcess(STATUS_FAILED); } if (bwrote < datasize ) { fprintf(stdout,"Wrote %d bytes\n",bwrote); } // 开始接收目标机器返回的信息 bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,&fromlen); if (bread == SOCKET_ERROR) { if (WSAGetLastError() == WSAETIMEDOUT) { printf("timed out\n"); continue; } fprintf(stderr,"recvfrom 失败: %d\n",WSAGetLastError()); perror("revffrom失败."); ExitProcess(STATUS_FAILED); } decode_resp(recvbuf,bread,&from); Sleep(1000); } closesocket(sockRaw); xfree(icmp_data); xfree(recvbuf); WSACleanup(); /* 清除 ws2_32.dll */ return 0; } |
![]() 图2 时间戳程序运行界面 |
英特尔 酷睿(TM)2双核,送指纹识别器一个,再赠两份好礼,请电800-858-2418