模拟ICMP过程
来源:互联网 发布:苹果mac os x 编辑:程序博客网 时间:2024/06/05 10:22
首先建立common头文件
//////////////////////////////////////////////////// comm.h文件// 包含一些公共函数#ifndef __COMM_H__#define __COMM_H__// 校验和的计算// 以16位的字为单位将缓冲区的内容相加,如果缓冲区长度为奇数,// 则再加上一个字节。它们的和存入一个32位的双字中USHORTchecksum(USHORT* buff, int size);BOOLSetTTL(SOCKET s, int nValue);BOOLSetTimeout(SOCKET s, int nTime, BOOL bRecv = TRUE);#endif // __COMM_H__
然后建立数据包头头文件
//////////////////////////////////////////////////// protoinfo.h文件/*定义协议格式定义协议中使用的宏 */#include <windows.h>#ifndef __PROTOINFO_H__#define __PROTOINFO_H__#define ETHERTYPE_IP 0x0800#define ETHERTYPE_ARP 0x0806typedef struct _ETHeader // 14字节的以太头{UCHARdhost[6];// 目的MAC地址destination mac addressUCHARshost[6];// 源MAC地址source mac addressUSHORTtype;// 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等} ETHeader, *PETHeader;#define ARPHRD_ETHER 1// ARP协议opcodes#defineARPOP_REQUEST1// ARP 请求#defineARPOP_REPLY2// ARP 响应typedef struct _ARPHeader// 28字节的ARP头{USHORThrd;//硬件地址空间,以太网中为ARPHRD_ETHERUSHORTeth_type;// 以太网类型,ETHERTYPE_IP ??UCHARmaclen;//MAC地址的长度,为6UCHARiplen;//IP地址的长度,为4USHORTopcode;//操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应UCHARsmac[6];//源MAC地址UCHARsaddr[4];//源IP地址UCHARdmac[6];//目的MAC地址UCHARdaddr[4];//目的IP地址} ARPHeader, *PARPHeader;// 协议#define PROTO_ICMP 1#define PROTO_IGMP 2#define PROTO_TCP 6#define PROTO_UDP 17typedef struct _IPHeader// 20字节的IP头{ UCHAR iphVerLen; // 版本号和头长度(各占4位) UCHAR ipTOS; // 服务类型 USHORT ipLength; // 封包总长度,即整个IP报的长度 USHORT ipID; // 封包标识,惟一标识发送的每一个数据报 USHORT ipFlags; // 标志 UCHAR ipTTL; // 生存时间,就是TTL UCHAR ipProtocol; // 协议,可能是TCP、UDP、ICMP等 USHORT ipChecksum; // 校验和 ULONG ipSource; // 源IP地址 ULONG ipDestination; // 目标IP地址} IPHeader, *PIPHeader; // 定义TCP标志#define TCP_FIN 0x01#define TCP_SYN 0x02#define TCP_RST 0x04#define TCP_PSH 0x08#define TCP_ACK 0x10#define TCP_URG 0x20#define TCP_ACE 0x40#define TCP_CWR 0x80typedef struct _TCPHeader// 20字节的TCP头{USHORTsourcePort;// 16位源端口号USHORTdestinationPort;// 16位目的端口号ULONGsequenceNumber;// 32位序列号ULONGacknowledgeNumber;// 32位确认号UCHARdataoffset;// 高4位表示数据偏移UCHARflags;// 6位标志位//FIN - 0x01//SYN - 0x02//RST - 0x04 //PUSH- 0x08//ACK- 0x10//URG- 0x20//ACE- 0x40//CWR- 0x80USHORTwindows;// 16位窗口大小USHORTchecksum;// 16位校验和USHORTurgentPointer;// 16位紧急数据偏移量 } TCPHeader, *PTCPHeader;typedef struct _UDPHeader{USHORTsourcePort;// 源端口号USHORTdestinationPort;// 目的端口号USHORTlen;// 封包长度USHORTchecksum;// 校验和} UDPHeader, *PUDPHeader;#endif // __PROTOINFO_H__
common.cpp
//////////////////////////////////////////////////// comm.cpp文件#include <winsock2.h>#include "Ws2tcpip.h"#include "common.h"#include <windows.h>USHORT checksum(USHORT* buff, int size){unsigned long cksum = 0;while(size>1){cksum += *buff++;size -= sizeof(USHORT);}// 是奇数if(size){cksum += *(UCHAR*)buff;}// 将32位的chsum高16位和低16位相加,然后取反cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >> 16);return (USHORT)(~cksum);}BOOL SetTTL(SOCKET s, int nValue){int ret = ::setsockopt(s, IPPROTO_IP, IP_TTL, (char*)&nValue, sizeof(nValue));return ret != SOCKET_ERROR;}BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv){int ret = ::setsockopt(s, SOL_SOCKET, bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));return ret != SOCKET_ERROR;}
最后是主文件,接受ICMP回送应答报文。type为0 code为0
///////////////////////////////////////////// ping.cpp文件#include "protoinfo.h"#include "common.h"#include <iostream>#include <stdio.h>typedef struct icmp_hdr{ unsigned char icmp_type;// 消息类型 unsigned char icmp_code;// 代码 unsigned short icmp_checksum;// 校验和// 下面是回显头 unsigned short icmp_id;// 用来惟一标识此请求的ID号,通常设置为进程ID unsigned short icmp_sequence;// 序列号 unsigned long icmp_timestamp; // 时间戳} ICMP_HDR, *PICMP_HDR;int main(){// 目的IP地址,即要Ping的IP地址char szDestIp[] = "115.25.217.12";// 127.0.0.1WSAData w;if(WSAStartup(MAKEWORD(2,2),&w)==SOCKET_ERROR)return -1;// 创建原始套节字SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);int time=1500;setsockopt(sRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&time,sizeof(int));// 设置接收超时// 设置目的地址SOCKADDR_IN dest;dest.sin_family = AF_INET;dest.sin_port = htons(0);dest.sin_addr.S_un.S_addr = inet_addr(szDestIp);// 创建ICMP封包char buff[sizeof(ICMP_HDR) + 32];ICMP_HDR* pIcmp = (ICMP_HDR*)buff;// 填写ICMP封包数据,请求一个ICMP回显pIcmp->icmp_type = 8;pIcmp->icmp_code = 0;pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();pIcmp->icmp_checksum = 0;pIcmp->icmp_sequence = 0;// 填充数据部分,可以为任意memset(&buff[sizeof(ICMP_HDR)], 'E', 32);// 开始发送和接收ICMP封包USHORTnSeq = 0;char recvBuf[1024];SOCKADDR_IN from;int nLen = sizeof(from);while(TRUE){static int nCount = 0;int nRet;// ping次数if(nCount++ == 1000)break;pIcmp->icmp_checksum = 0;pIcmp->icmp_timestamp = ::GetTickCount();pIcmp->icmp_sequence = nSeq++;pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32);nRet = ::sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest));if(nRet == SOCKET_ERROR){printf(" sendto() failed: %d /n", ::WSAGetLastError());return -1;}nRet = ::recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);if(nRet == SOCKET_ERROR){if(::WSAGetLastError() == WSAETIMEDOUT){printf(" timed out/n");continue;}printf(" recvfrom() failed: %d\n", ::WSAGetLastError());return -1;}// 下面开始解析接收到的ICMP封包int nTick = ::GetTickCount();if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR)){printf(" Too few bytes from %s \n", ::inet_ntoa(from.sin_addr));}// 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头// (ICMP_HDR*)(recvBuf + sizeof(IPHeader));ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); if(pRecvIcmp->icmp_type != 0)// 回显{printf(" nonecho type %d recvd \n", pRecvIcmp->icmp_type);printf("should quit\n");return -1;}if(pRecvIcmp->icmp_id != ::GetCurrentProcessId()){printf(" someone else's packet! \n");printf("should quit\n");return -1;}printf("从 %s 返回 %d 字节:\n", inet_ntoa(from.sin_addr),nRet);printf(" 数据包序列号 = %d. \t", pRecvIcmp->icmp_sequence);printf(" 延时大小: %d ms\n", nTick - pRecvIcmp->icmp_timestamp);printf(" \n");// 每一秒发送一次就行了::Sleep(1000);}return 0;}
0 0
- 模拟ICMP过程
- VC模拟ping发送ICMP数据包
- VC模拟ping发送ICMP数据包
- ICMP
- ICMP
- ICMP
- ICMP
- icmp
- ICMP
- icmp
- icmp
- ICMP
- ICMP
- ICMP
- ICMP
- ICMP
- ICMP
- ICMP
- 九度oj-1084-整数拆分
- Android开发-使用自定义View实现loading效果
- 锤子T2参数全曝光:骁龙808基本没跑了
- 四大因素决定 浅析iOS为什么比安卓流畅
- hive insert overwrite1.2.1 无法删除旧文件的问题
- 模拟ICMP过程
- 使用BinaryWriter写文件第一个字符是乱码是什么原因?
- Linux指令--chown
- Mongodb数据导出工具mongoexport和导入工具mongoimport介绍
- Linux命令行测试网速
- Java习惯用法总结
- ROCK (RObust Clustering using linKs)
- [网络] 大话IP地址
- OpenSSL命令---pkcs8