基于icmp的tracert路由追踪程序
https://blog.csdn.net/u013271921/article/details/45488173
#include<winsock2.h>
//#include<iphlpapi.h>
#include <Ws2tcpip.h>
#include<iostream>
#include<conio.h>
//#include<bits/stdc++.h>
using namespace std; const BYTE ICMP_ECHO_REQUEST = ;//请求回显
const BYTE ICMP_ECHO_REPLY = ;//回显应答
const BYTE ICMP_TIMEOUT = ;//传输超时
const int DEF_ICMP_DAtA_SIZE = ;//ICMP报文默认数据字段长度
const int MAX_ICMP_PACKET_SIZE = ;//ICMP报文最大长度(包含报头)
const DWORD DEF_ICMP_TIMEOUT = ;//回显应答超时时间,单位ms
const int DEF_MAX_HOP = ;//最大跳站数 typedef struct {
BYTE hdr_len :;//4位头部长度
BYTE version :;//长度版本号
BYTE tos;//8位服务类型
USHORT total_len;//16位总长度
USHORT identifier;//16位标识符
USHORT frag_and_flags;//3位标志+13位片偏移
BYTE ttl;//8位生存时间
BYTE protocol;//8位上层协议号
USHORT checksum;//16位校验和
ULONG sourceIP;//32位源IP地址
ULONG destIP;//32位目的IP地址
} IP_HEADER; typedef struct {
BYTE type;//8位类型字段
BYTE code;//8位代码字段
USHORT cksum;//16为校验和
USHORT id;//16位标识符
USHORT seq;//16位序列号
} ICMP_HEADER; typedef struct {
// 序列号(输入参数)
USHORT usSeqNo;
// 往返时间(输入、输出)
DWORD dwRoundTripTime;
// 返回报文的IP地址(输出参数)
in_addr dwIpAddr;
} DECODE_RESULT; //计算网际校验和函数
USHORT checksum(USHORT* pBuf, int iSize) {
ULONG cksum = ;
while(iSize > ) {
cksum += *pBuf++;
iSize -= sizeof(USHORT);
}
// 如果 iSize 为正,即为奇数个字节
if(iSize) {
// 则在末尾补上一个字节,使之有偶数个字节
cksum += *(UCHAR*)pBuf;
}
cksum = (cksum>>) +(cksum & 0xffff);
cksum += (cksum >> );
return (USHORT)(~cksum);
} bool DecodeIcmpResponse(char *pBuf, int iPacketSize, DECODE_RESULT& DecodeResult) {
// 计算IP头部长度
int iIpHdrLen = ((IP_HEADER*)pBuf)->hdr_len * ;
// 根据ICMP报文类型提取ID字段和序列号字段
ICMP_HEADER *pIcmpHdr = (ICMP_HEADER *)(pBuf + iIpHdrLen);
USHORT usID;
USHORT usSquNo;
// ICMP回显应答报文
if(pIcmpHdr->type == ICMP_ECHO_REPLY) {
// 报文ID
usID = pIcmpHdr->id;
// 序列号
usSquNo = pIcmpHdr->seq;
}
// ICMP超时差错报文
else if(pIcmpHdr->type == ICMP_TIMEOUT) {
// 载荷中的IP头
char *pInnerIpHdr = pBuf + iIpHdrLen + sizeof(ICMP_HEADER);
// 载荷中的IP头长
int iInnerIpHdrLen = ((IP_HEADER*)pInnerIpHdr)->hdr_len * ;
// 载荷中的ICMP头
ICMP_HEADER *pInnerIcmpHdr = (ICMP_HEADER*)(pInnerIpHdr + iInnerIpHdrLen);
// 报文ID
usID = pInnerIcmpHdr->id;
// 序列号
usSquNo = pInnerIcmpHdr->seq;
}
else {
return false;
}
// printf("usID: %d == currentID: %d\n", usID, (USHORT)GetCurrentProcessId());
// printf("usSquNo: %d == DecodeResult: %d\n", usSquNo, DecodeResult.usSeqNo);
// 检查ID和序列号以确定收到期待数据报
if(usID != (USHORT)GetCurrentProcessId() || usSquNo != DecodeResult.usSeqNo) {
return false;
}
// 记录IP地址并计算往返时间
DecodeResult.dwIpAddr.s_addr = ((IP_HEADER*)pBuf)->sourceIP;
DecodeResult.dwRoundTripTime = GetTickCount() - DecodeResult.dwRoundTripTime;
// 打印往返时间信息
if(DecodeResult.dwRoundTripTime) {
cout << " " << DecodeResult.dwRoundTripTime << "ms" << flush;
}
else {
cout << " " << "<1" << "ms" << flush;
}
return true;
} WSADATA wsa;
char IcmpSendBuf[sizeof(ICMP_HEADER) + DEF_ICMP_DAtA_SIZE];//发送缓冲区
char IcmpRecvBuf[sizeof(ICMP_HEADER) + DEF_ICMP_DAtA_SIZE];//接收缓冲区
char argv[][];
int main() {
WSAStartup(MAKEWORD(, ), &wsa);
//将命令行参数转换成IP地址
scanf("%s", argv[]);
ULONG ulDestIP = inet_addr(argv[]);
if(ulDestIP == INADDR_NONE) {
//转换不成功时按域名解析
hostent *pHostent = gethostbyname(argv[]);
if(pHostent) ulDestIP = (*(in_addr*) pHostent->h_addr).s_addr;
else {
WSACleanup();
return -;
}
}
//填充目的端socket地址。
sockaddr_in destSockAddr;
ZeroMemory(&destSockAddr, sizeof(sockaddr_in));
destSockAddr.sin_family = AF_INET;
destSockAddr.sin_addr.s_addr = ulDestIP;
SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, , WSA_FLAG_OVERLAPPED);
int iTimeout = ;
//设置超时机制
setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*) &iTimeout, sizeof(iTimeout));
setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char*) &iTimeout, sizeof(iTimeout));
ICMP_HEADER *pIcmpHeader = (ICMP_HEADER*) IcmpSendBuf;
pIcmpHeader->type = ICMP_ECHO_REQUEST;//类型为请求回显
pIcmpHeader->code = ;//代码字段为0
pIcmpHeader->id=(USHORT)GetCurrentProcessId();//ID字段为当前进程号
memset(IcmpSendBuf + sizeof(ICMP_HEADER), 'E', DEF_ICMP_DAtA_SIZE);//数据字段
USHORT usSeqNo = ;//ICMP报文序列号
int iTTL = ;//TTL初始值为1
bool bReachDestHost = false;//循环退出标志
int iMaxHop = DEF_MAX_HOP;//循环的最大次数
DECODE_RESULT DecodeResult;//传递给报文解码函数的结构化参数
while(!bReachDestHost && iMaxHop--) {
//设置IP报头的TTL字段
setsockopt(sockRaw, IPPROTO_IP, IP_TTL, (char*)&iTTL, sizeof(iTTL));
cout << iTTL << flush;//输出当前序号
//填充ICMP报文中每次发送时需要变化的字段
((ICMP_HEADER*)IcmpSendBuf)->cksum = ;//校验和先置为0
((ICMP_HEADER*)IcmpSendBuf)->seq = htons(usSeqNo++);//填充序列号
//计算校验和
((ICMP_HEADER*)IcmpSendBuf)->cksum = checksum((USHORT*)IcmpSendBuf, sizeof(ICMP_HEADER) + DEF_ICMP_DAtA_SIZE);
DecodeResult.usSeqNo = ((ICMP_HEADER*)IcmpSendBuf)->seq;//当前序号
DecodeResult.dwRoundTripTime = GetTickCount();//当前时间
//发送ICMP回显请求消息
sendto(sockRaw, IcmpSendBuf, sizeof(IcmpSendBuf), , (sockaddr*)&destSockAddr, sizeof(destSockAddr));
// 接收ICMP报文
// 对端Socket地址
sockaddr_in from;
// 地址结构大小
int iFromLen = sizeof(from);
// 接收数据长度
int iReadDataLen;
// 循环接收直到收到所需数据或超时
while() {
iReadDataLen = recvfrom(sockRaw, IcmpRecvBuf, MAX_ICMP_PACKET_SIZE, , (sockaddr*)&from, &iFromLen);
// 有数据到达
if(iReadDataLen != SOCKET_ERROR) {
// 对数据包进行解析
if(DecodeIcmpResponse(IcmpRecvBuf, iReadDataLen, DecodeResult)) {
// 到达目的地,退出循环
if(DecodeResult.dwIpAddr.s_addr == destSockAddr.sin_addr.s_addr) {
bReachDestHost = true;
// printf("reach\n");
}
// 打印IP地址
cout << '\t' << inet_ntoa(DecodeResult.dwIpAddr) << endl;
break;
}
}
// 接收超时,打印*号
else if(WSAGetLastError() == WSAETIMEDOUT) {
cout << " " << '*' << '\t' << "Request timed out." << endl;
break;
}
}
iTTL++;
}
cout << "reach: " << bReachDestHost << endl;
return ;
} //cqupt 202.202.32.35
//csdn 39.96.126.153
//cnblogs 101.37.113.127
基于icmp的tracert路由追踪程序的更多相关文章
- ping命令基于ICMP协议的返回信息分析
Ping是潜水艇人员的专用术语,表示回应的声纳脉冲,在网络中 Ping 是一个十分好用的 TCP/IP 工具.它主要的功能是用来检测网络的连通情况和分析网络速度.可以利用 PING 命令检查网络连通状 ...
- 建立tracert路由列表的方法
建立tracert路由列表的方法:电脑屏幕左下方 选择开始选项运行 输入 CMD在DOS命令行下输入:tracert (你的网站域名) 运行结果中如出现了“* * * req ...
- 第二百六十四节,Tornado框架-基于正则的动态路由映射分页数据获取计算
Tornado框架-基于正则的动态路由映射分页数据获取计算 分页基本显示数据 第一步.设置正则路由映射配置,(r"/index/(?P<page>\d*)", inde ...
- 第二百六十三节,Tornado框架-基于正则的动态路由映射
Tornado框架-基于正则的动态路由映射 1.在路由映射条件里用正则匹配访问路径后缀2.给每一个正则匹配规则(?P<设置名称>)设置一个名称,3.在逻辑处理的get()方法或post() ...
- tracert路由跟踪命令分析判断
可能有的会使用路由跟踪命令 ,可是却看不太明确显示出来的结果.结合我的来说明一下. (1)tracert命令介绍 tracert是路由跟踪命令,通过该命令的返回结果,能够获得本地到达目标主机所经过的网 ...
- tracert路由跟踪工具使用方法
1. 路由跟踪在线Tracert工具说明 Tracert(跟踪路由)是路由跟踪实用程序,用于确定 IP 数据报访问目标所采取的路径.Tracert 命令用 IP 生存时间 (TTL) 字段和 ICMP ...
- 基于TCAM 的高速路由查找
摘要 随着路由器接口速率的提高,传统的软件路由查找机制已经不能满足要求.目前常见的硬件解决方案是采用TCAM实现关键词 TCAM,路由查找,最长前缀匹配. 1.引言 路由器转发IP 分组时,转发引擎需 ...
- tracert 路由跟踪程序
C:\Users\Administrator>tracert 10.0.0.1 通过最多 30 个跃点跟踪到 10.0.0.1 的路由 1 <1 毫秒 1 ms 3 ms 192.168. ...
- 基于原生PHP的路由分配实现
对于由原生PHP写成的独立PHP框架,利用单一入口文件实现路径的访问.这时我们会遇到的首要问题是:文件的相互包含,其次就是路由分配.当我们不利用成熟的PHP框架进行web开发时,我们就会发现上述两个问 ...
随机推荐
- 【Unity|C#】基础篇(19)——集合库(Collections)
[学习资料] <C#图解教程>(第6章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu.c ...
- CSS-使用CSS样式的方式
1.HTML<!DOCTYPE>声明标签 (1)定义和用法 <!DOCTYPE>声明必须是HTML文档的第一行,位于<html>标签之前. <!DOCTYPE ...
- TCP/IP协议和socket
1.传输层基于tcp协议的三次握手和四次挥手? 传输层有两种数据传输协议,分别为TCP协议和UDP协议,其中TCP协议为可靠传输,数据包没有长度设置,理论可以无限长,而UDP协议为不可靠传输,报头一共 ...
- 远程执行命令_python
一.远程执行命令模块subprocess Python可以使用subprocess下的Popen类中的封装的方法来执行命令 构造方法 popen() 创建popen类的实例化对象 ··· obj = ...
- [TJOI2007] 路标设置 - 二分答案,贪心
考虑到答案满足可二分性,段内可以贪心,所以暴力二分即可 注意-1 详见代码(我这题都能写WA) #include <bits/stdc++.h> using namespace std; ...
- 154.Ajax处理csrf防御
在普通的form表单中采用post请求提交数据,可以在form表单的method=post的form标签下面,添加一个csrf_token标签{% csrf_token %},或者是直接手动的添加一个 ...
- Linux終端一行命令发送邮件
近期由于经常需要给别人发送邮件,每次都要打开QQ邮箱觉得非常麻烦.想到Linux终端可以自定义命令,加上python可以实现邮件发送功能,于是自己写了一个终端send + 文件地址的命令. 首先贴上p ...
- SQLServer2005:在执行时出现错误。错误消息为: 目录名无效
删除数据时忘了想delete删除的话会记录日志,更何况是我删除百万条数据,结果还没删完服务器内存就占慢了,一切数据都进不来了,估计这种情况导致我的数据库有问题了,右键打开表提示:目录名无效,执行SQL ...
- 巨杉Tech|SequoiaDB 巨杉数据库高可用容灾测试
数据库的高可用是指最大程度地为用户提供服务,避免服务器宕机等故障带来的服务中断.数据库的高可用性不仅仅体现在数据库能否持续提供服务,而且也体现在能否保证数据的一致性. SequoiaDB 巨杉数据库作 ...
- 07 部署fastDFS文件数据库
安装fastDFS前必须准备好两个版本匹配的文件: libfastcommon_V1.0.7.tar.gz:基础库文件 FastDFS_V5.05.tar.gz:文件数据库文件 注:这两个文件版本要匹 ...