ping程序
2016-05-19 16:25
309 查看
protoinfo.h
//////////////////////////////////////////////////
// protoinfo.h文件
/*
定义协议格式
定义协议中使用的宏
*/
#ifndef __PROTOINFO_H__
#define __PROTOINFO_H__
#define ETHERTYPE_IP 0x0800
#define ETHERTYPE_ARP 0x0806
typedef struct _ETHeader // 14字节的以太头
{
UCHAR dhost[6]; // 目的MAC地址destination mac address
UCHAR shost[6]; // 源MAC地址source mac address
USHORT type; // 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等
} ETHeader, *PETHeader;
#define ARPHRD_ETHER 1
// ARP协议opcodes
#define ARPOP_REQUEST 1 // ARP 请求
#define ARPOP_REPLY 2 // ARP 响应
typedef struct _ARPHeader // 28字节的ARP头
{
USHORT hrd; // 硬件地址空间,以太网中为ARPHRD_ETHER
USHORT eth_type; // 以太网类型,ETHERTYPE_IP ??
UCHAR maclen; // MAC地址的长度,为6
UCHAR iplen; // IP地址的长度,为4
USHORT opcode; // 操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应
UCHAR smac[6]; // 源MAC地址
UCHAR saddr[4]; // 源IP地址
UCHAR dmac[6]; // 目的MAC地址
UCHAR daddr[4]; // 目的IP地址
} ARPHeader, *PARPHeader;
// 协议
#define PROTO_ICMP 1
#define PROTO_IGMP 2
#define PROTO_TCP 6
#define PROTO_UDP 17
typedef 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 0x80
typedef struct _TCPHeader // 20字节的TCP头
{
USHORT sourcePort; // 16位源端口号
USHORT destinationPort; // 16位目的端口号
ULONG sequenceNumber; // 32位序列号
ULONG acknowledgeNumber; // 32位确认号
UCHAR dataoffset; // 高4位表示数据偏移
UCHAR flags; // 6位标志位
//FIN - 0x01
//SYN - 0x02
//RST - 0x04
//PUSH- 0x08
//ACK- 0x10
//URG- 0x20
//ACE- 0x40
//CWR- 0x80
USHORT windows; // 16位窗口大小
USHORT checksum; // 16位校验和
USHORT urgentPointer; // 16位紧急数据偏移量
} TCPHeader, *PTCPHeader;
typedef struct _UDPHeader
{
USHORT sourcePort; // 源端口号
USHORT destinationPort;// 目的端口号
USHORT len; // 封包长度
USHORT checksum; // 校验和
} UDPHeader, *PUDPHeader;
#endif // __PROTOINFO_H__
comm.h
//////////////////////////////////////////////////
// comm.h文件
// 包含一些公共函数
#ifndef __COMM_H__
#define __COMM_H__
// 校验和的计算
// 以16位的字为单位将缓冲区的内容相加,如果缓冲区长度为奇数,
// 则再加上一个字节。它们的和存入一个32位的双字中
USHORT checksum(USHORT* buff, int size);
BOOL SetTTL(SOCKET s, int nValue);
BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv = TRUE);
#endif // __COMM_H__
comm.cpp
//////////////////////////////////////////////////
// comm.cpp文件
#include <winsock2.h>
#include <windows.h>
#include "Ws2tcpip.h"
#include "comm.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;
}
//////////////////////////////////////////////////
// protoinfo.h文件
/*
定义协议格式
定义协议中使用的宏
*/
#ifndef __PROTOINFO_H__
#define __PROTOINFO_H__
#define ETHERTYPE_IP 0x0800
#define ETHERTYPE_ARP 0x0806
typedef struct _ETHeader // 14字节的以太头
{
UCHAR dhost[6]; // 目的MAC地址destination mac address
UCHAR shost[6]; // 源MAC地址source mac address
USHORT type; // 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等
} ETHeader, *PETHeader;
#define ARPHRD_ETHER 1
// ARP协议opcodes
#define ARPOP_REQUEST 1 // ARP 请求
#define ARPOP_REPLY 2 // ARP 响应
typedef struct _ARPHeader // 28字节的ARP头
{
USHORT hrd; // 硬件地址空间,以太网中为ARPHRD_ETHER
USHORT eth_type; // 以太网类型,ETHERTYPE_IP ??
UCHAR maclen; // MAC地址的长度,为6
UCHAR iplen; // IP地址的长度,为4
USHORT opcode; // 操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应
UCHAR smac[6]; // 源MAC地址
UCHAR saddr[4]; // 源IP地址
UCHAR dmac[6]; // 目的MAC地址
UCHAR daddr[4]; // 目的IP地址
} ARPHeader, *PARPHeader;
// 协议
#define PROTO_ICMP 1
#define PROTO_IGMP 2
#define PROTO_TCP 6
#define PROTO_UDP 17
typedef 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 0x80
typedef struct _TCPHeader // 20字节的TCP头
{
USHORT sourcePort; // 16位源端口号
USHORT destinationPort; // 16位目的端口号
ULONG sequenceNumber; // 32位序列号
ULONG acknowledgeNumber; // 32位确认号
UCHAR dataoffset; // 高4位表示数据偏移
UCHAR flags; // 6位标志位
//FIN - 0x01
//SYN - 0x02
//RST - 0x04
//PUSH- 0x08
//ACK- 0x10
//URG- 0x20
//ACE- 0x40
//CWR- 0x80
USHORT windows; // 16位窗口大小
USHORT checksum; // 16位校验和
USHORT urgentPointer; // 16位紧急数据偏移量
} TCPHeader, *PTCPHeader;
typedef struct _UDPHeader
{
USHORT sourcePort; // 源端口号
USHORT destinationPort;// 目的端口号
USHORT len; // 封包长度
USHORT checksum; // 校验和
} UDPHeader, *PUDPHeader;
#endif // __PROTOINFO_H__
comm.h
//////////////////////////////////////////////////
// comm.h文件
// 包含一些公共函数
#ifndef __COMM_H__
#define __COMM_H__
// 校验和的计算
// 以16位的字为单位将缓冲区的内容相加,如果缓冲区长度为奇数,
// 则再加上一个字节。它们的和存入一个32位的双字中
USHORT checksum(USHORT* buff, int size);
BOOL SetTTL(SOCKET s, int nValue);
BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv = TRUE);
#endif // __COMM_H__
comm.cpp
//////////////////////////////////////////////////
// comm.cpp文件
#include <winsock2.h>
#include <windows.h>
#include "Ws2tcpip.h"
#include "comm.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;
}
#include <winsock2.h> #include <stdio.h> #include "../common/protoinfo.h" #include "../common/comm.h" #pragma comment(lib, "WS2_32.lib") 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(void) { WSADATA wsaData; WORD sockVersion = MAKEWORD(2, 0); WSAStartup(sockVersion, &wsaData); // 目的IP地址,即要Ping的IP地址 char szDestIp[] = "218.85.152.99"; // 127.0.0.1 // 创建原始套节字 SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); // 设置接收超时 SetTimeout(sRaw, 1000, TRUE); // 设置目的地址 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]={0}; ICMP_HDR* pIcmp = (ICMP_HDR*)buff; // 填写ICMP封包数据 pIcmp->icmp_type = 8; // 请求一个ICMP回显 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封包 USHORT nSeq = 0; char recvBuf[1024]; SOCKADDR_IN from; int nLen = sizeof(from); while(TRUE) { static int nCount = 0; int nRet; 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* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // (ICMP_HDR*)(recvBuf + sizeof(IPHeader)); if(pRecvIcmp->icmp_type != 0) // 回显 { printf(" nonecho type %d recvd \n", pRecvIcmp->icmp_type); return -1; } if(pRecvIcmp->icmp_id != ::GetCurrentProcessId()) { printf(" someone else's packet! \n"); return -1; } printf(" %d bytes from %s:", nRet, inet_ntoa(from.sin_addr)); printf(" icmp_seq = %d. ", pRecvIcmp->icmp_sequence); printf(" time: %d ms", nTick - pRecvIcmp->icmp_timestamp); printf(" \n"); ::Sleep(1000); } WSACleanup(); return 0; }
相关文章推荐
- structs2 S-019漏洞修复
- CP_THREAD_ACP与CP_ACP区别
- pomelo
- web大文件上传控件-监控fd_create流程-Xproer.HttpUploader6
- oracle数据库表,索引创建实例
- Sublime text 的配置
- 整理GCD用法
- WinSCP 5.6版本中文目录乱码问题解决方案
- Android-SDK-For-Linux常用命令
- iOS多线程使用总结
- OSSIM入门 最新课程 (时长5小时20分)
- Oracle Indexes(索引)
- 度量快速开发平台网格勾选行(标识行),多选行获取方法
- 浅析Java中的XML
- 如何建立起一套有效的APP监控体系
- 指针和引用的参数传递
- Leetcode 171. Excel Sheet Column Number
- Android APP增量升级的实现方式
- 带下划线的EditText
- STL算法总结之查找算法示例