基于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开发时,我们就会发现上述两个问 ...
随机推荐
- 【vue 权威指南】 学习笔记 二
1.指令 1.1内部指令 基础指令:v-show , v-else , v-model , v-repeat , v-for , v-text , v-el , v-html , v-on , v-b ...
- 爬虫学习笔记2requests库和beautifulsoup4库学习笔记
目录 1.requests库 1.1 安装 2.beautifulsoup4 2.1 常用方法 2.2 bs4 中四大对象种类 2.3 遍历文档树 2.4 搜索文档树 查询id=head的Tag 查询 ...
- 云服务器 使用 onedrive 快速同步
重大更新:支持微软的onedrive网盘,可以自动实时双向同步数据,也可以多台服务器和网盘之间实时同步数据.新增了一个虚拟环境python367,支持pytorch1.2:-----------微软O ...
- django Warning: (3135, "'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes
django连接数据库配置设置如下 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'test2', ...
- nginx 启动报错找不到nginx.pid文件
这个问题的出现应该是系统找不到nginx的配置文件nginx.conf,所以,我们要告诉系统配置文件的位置:' --- 使用nginx -c /usr/local/nginx/conf/nginx.c ...
- HashMap,ConcurrentHashMap原理。Collection(list,set,map集合区别)。和CAS
collection里面有什么子类?(list和set是实现了collection接口的.) List: 1.可以允许重复的对象(可重复,有序集合).2.可以插入多个null元素.3.常用的实现类有 ...
- HTML /和./的区别 - Web开发
"/"访问根目录 例1 https://www.cnblogs.com/test 里有 <a href="/Edsuns"></a> 则 ...
- react中用swiper实现大图功能
1.引入Swiper(用的是4.5.0版本) import Swiper from 'swiper'; //引入样式,还可以加上自己的样式 import '../../s ...
- 一点点学习PS--实战五
本节实战的内容,新学习到的功能是:人物影子边缘.立体的心形 1.工具的使用: (1)滤镜--模糊--特殊模糊 (2)滤镜--滤镜库--艺术效果--水彩 (3)滤镜--滤镜库--纹理化 (4)自动形状工 ...
- eclipse的安装和环境配置
一,eclipse下载 地址:https://www.eclipse.org/downloads/ 一般浏览器都有翻译功能 二.有32位和64位的版本根据自己的需求下载,选下载的选下载量最多的下载. ...