什么是traceroute?Linux C/C++下利用ICMP实现traceroute

2024-02-24 16:10
文章标签 c++ 实现 linux icmp traceroute

本文主要是介绍什么是traceroute?Linux C/C++下利用ICMP实现traceroute,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Linux 中的 traceroute 是一个命令,它是网络工程师用来排除网络故障的最流行的工具, 它于 1987 年发明。

当您连接到网站时,您获得的数据必须沿途跨多个设备和网络传输,尤其是路由器。 跟踪路由提供了 Internet 上的数据如何从其源传输到其目的地的信息。

如何运行跟踪路由

在 Linux 系统上运行 traceroute,请执行以下操作

traceroute [hostname]

在这里插入图片描述

在 Windows 系统上,请执行以下操作:

tracert [hostname]

在这里插入图片描述
术语“主机名”或主机是您感兴趣的网站或服务器、路由器或设备的 IP 地址。 traceroute 报告此目标点。 跟踪路由完成后,它会自行终止。

traceroute 和 tracert 完成相同的一般功能。 唯一显着的区别是命令在Linux 系统上是“traceroute”,在 Windows 系统上是“tracert”。

traceroute 有什么作用?

跟踪路由的工作原理是发送 Internet 控制消息协议 (ICMP) 数据包,并且每个参与传输数据的路由器都会获取这些数据包。 ICMP 数据包提供有关传输中使用的路由器是否能够有效传输数据的信息。

traceroute 使用 TTL 表示 IP 数据包中的 Time To Live,TTL 用于防止网络中的环路,当 IP 数据包从一个路由器转发到另一个路由器时,它将 TTL 值减一,当 TTL 值将 零,数据包将被丢弃。

在这里插入图片描述
traceroute 为每个 HOP 发送三个数据包以获得往返时间。三个数据包中的 TTL 字段最初设置为 1,之后第一个路由器生成一个 ICMP Time Exceeded 消息给发送方。发送方在时间戳字段和路由器的IP地址中记录往返延迟,并发送另一组数据包,这次TTL设置为2。

在这里插入图片描述第二个路由器丢弃数据包,并发送回另一个 ICMP Time Exceeded? 消息。 重复该过程直到到达目标主机。

ICMP Echo (ping),然后 Type 字段的值为 8。
如果是 ICMP Echo Reply(ping 回复),那么它的值为 1。
Time Exceeded?消息值为 3。

traceroute 用于什么?

Internet 协议 (IP) 跟踪器有助于确定数据必须经过的路由跳数,以及数据在跨节点传输时的响应延迟,这些节点是将数据发送到目的地的原因。

traceroute 还使您能够定位数据无法发送的位置,称为故障点。 您还可以执行可视化跟踪路由以获得每个跃点的可视化表示。

如何阅读跟踪路由报告

traceroute 报告列出了数据包在到达目的地时所经过的每个路由器的相关数据。报告中的每一行都有域名(如果包含)以及属于路由器的 IP 地址。

在这里插入图片描述
还有三个时间测量值,以毫秒为单位显示。这些告诉您将 ICMP 数据包从您的计算机发送到该路由器并返回的时间长度。

**你看到星号了吗? **

有时,traceroute 很难访问设备或无法访问。 在这些情况下,它可能会显示一条消息“请求超时”,并带有星号。

这表明它到达的路由器被配置为降低优先级或自动拒绝 ICMP 数据包,这是因为 ICMP 未被许多路由器归类为基本流量。

什么因素影响跳跃时间?

计算机与其最终目的地之间的物理距离是影响跳跃时间的主要因素之一。网络故障排除时应牢记这一点。距离越大,跳跃时间越长。

另一个促成因素是促进每一跳的连接类型。连接速度更快的计算机,例如使用千兆以太网的计算机,很可能比连接速度较慢的计算机提供更快的跳数。

此外,数据的传递方式可能会有所不同。例如,如果数据通过多台设备共享的无线路由器发送,则往返时间可能比通过以太网或光纤连接专用于一台计算机的路由器慢。

traceroute 使用 TTL来发现源和目标之间的路由器

在 IP 标头中,有一个称为生存时间 (TTL) 的 8 位字段,从 0 到 255。每次数据包通过路由器路由时,TTL 的值都会递减 1。 当 TTL 值为 0 时,数据包将被丢弃,并且可能会将 ICMP TTL Exceeded 消息发送回数据包的源。

TTL 字段的主要目的不是跟踪路由,而是在网络中存在路由环路时丢弃数据包。 因此,如果存在循环,由于每个路由器都会递减 TTL 值,因此在某一时刻,它会变为 0 并被丢弃。因此,traceroute 命令使用 TTL 来发现源和目标之间的路由器。

在这里插入图片描述

  • 1.首先,源(Src)发送一个 TTL=1 的数据包。
  • 2.路由器将 TTL 递减 1,将值更改为 0。数据包被丢弃,路由器发送 ICMP TTL Exceeded 消息。 ICMP 消息的目的
    IP 地址等于丢弃数据包的源 IP 地址。 丢弃报文的源IP地址是接收报文的接口的IP地址。
  • 3.Source 收到“ICMP TTL Exceeded”消息,并将路由器 IP 添加到 Traceroute hops 表中。
  • 4.然后该过程以 TTL=2 重新开始。
  • 5.数据包通过第一个路由器 (R1) 路由,这也会减少数据包值。
  • 6.第二个路由器 (R2) 接收数据包,递减 TTL,丢弃数据包并发送“ICMP TTL Exceeded”消息。
  • 7.并且它通过将 TTL 增加 1 直到到达目的地继续这样下去。

利用ICMP实现traceroute

int main(int argc, char **argv)
{struct traceroute *t = traceroute_alloc();int op, code, n;char *cp;const char *err;u_int32_t *ap;int probe, i;int tos = 0, settos = 0;struct ifaddrlist *al;char errbuf[132];int requestPort = -1;int sump = 0;int sockerrno;const char devnull[] = "/dev/null";int printdiff = 0; /* Print the difference between sent and quoted */int ret;/* Insure the socket fds won't be 0, 1 or 2 */if (open(devnull, O_RDONLY) < 0 ||open(devnull, O_RDONLY) < 0 ||open(devnull, O_RDONLY) < 0) {fprintf(stderr, "%s: open \"%s\": %s\n",prog, devnull, strerror(errno));exit(1);}traceroute_init(t);ret = traceroute_set_proto(t, "icmp");if (ret != 0) {fprintf(stderr, "traceroute_set_proto failed: %i\n", ret);return ret;}if (argc != 2) {fprintf(stderr, "usage: traceroute hostname\n");return 1;}ret = traceroute_set_hostname(t, argv[1]);if (ret < 0) {fprintf(stderr, "traceroute_set_hostname failed\n");return 1;}ret = traceroute_bind(t);if (ret != 0) {fprintf(stderr, "traceroute_bind failed: %i\n", ret);return ret;}if (setuid(getuid()) != 0) {perror("setuid()");exit(1);}setvbuf(stdout, NULL, _IOLBF, 0);/* Print out header */fprintf(stderr, "%s to %s (%s)",prog, t->hostname, inet_ntoa(t->to->sin_addr));if (t->source)fprintf(stderr, " from %s", t->source);fprintf(stderr, ", %d hops max, %d byte packets\n", t->max_ttl, t->packlen);(void)fflush(stderr);TRACEROUTE_FOR_EACH_TTL(t) {u_int32_t lastaddr = 0;int gotlastaddr = 0;int got_there = 0;int unreachable = 0;int loss = 0;;int sleep_for = 1000;int max_sleep = 100;Printf("%2d ", t->ttl);for (probe = 0; probe < t->nprobes; ++probe) {int cc;struct ip *ip;int slept = 0;traceroute_send_next_probe(t);/* 等待回复  */cc = traceroute_wait_for_reply(t);while (cc == 0 && slept < max_sleep) {usleep(sleep_for);slept++;cc = traceroute_wait_for_reply(t);}while (cc != 0) {double T;int precis;i = traceroute_packet_ok(t, cc);/* 跳过短包  */if (i == 0)break;if (!gotlastaddr ||t->from->sin_addr.s_addr != lastaddr) {if (gotlastaddr) printf("\n   ");print(t, t->packet, cc, t->from);lastaddr = t->from->sin_addr.s_addr;++gotlastaddr;}T = traceroute_time_delta(t);
#ifdef SANE_PRECISIONif (T >= 1000.0)precis = 0;else if (T >= 100.0)precis = 1;else if (T >= 10.0)precis = 2;else
#endifprecis = 3;printf("  %.*f ms", precis, T);if (printdiff) {printf("\n");printf("%*.*s%s\n",-(t->outip->ip_hl << 3),t->outip->ip_hl << 3,ip_hdr_key,t->proto->key);pkt_compare((void *)t->outip, t->packlen,(void *)t->hip, t->hiplen);}if (i == -2) {
#ifndef ARCHAICip = (struct ip *)t->packet;if (ip->ip_ttl <= 1)printf(" !");
#endif++got_there;break;}/* time exceeded in transit */if (i == -1)break;code = traceroute_packet_code(t, cc);switch (code) {case ICMP_UNREACH_PORT:
#ifndef ARCHAICip = (struct ip *)t->packet;if (ip->ip_ttl <= 1)printf(" !");
#endif++got_there;break;case ICMP_UNREACH_NET:++unreachable;printf(" !N");break;case ICMP_UNREACH_HOST:++unreachable;printf(" !H");break;case ICMP_UNREACH_PROTOCOL:++got_there;Printf(" !P");break;case ICMP_UNREACH_NEEDFRAG:++unreachable;printf(" !F-%d", t->pmtu);break;case ICMP_UNREACH_SRCFAIL:++unreachable;printf(" !S");break;case ICMP_UNREACH_NET_UNKNOWN:++unreachable;printf(" !U");break;case ICMP_UNREACH_HOST_UNKNOWN:++unreachable;printf(" !W");break;case ICMP_UNREACH_ISOLATED:++unreachable;printf(" !I");break;case ICMP_UNREACH_NET_PROHIB:++unreachable;printf(" !A");break;case ICMP_UNREACH_HOST_PROHIB:++unreachable;printf(" !Z");break;case ICMP_UNREACH_TOSNET:++unreachable;printf(" !Q");break;case ICMP_UNREACH_TOSHOST:++unreachable;printf(" !T");break;case ICMP_UNREACH_FILTER_PROHIB:++unreachable;printf(" !X");break;case ICMP_UNREACH_HOST_PRECEDENCE:++unreachable;printf(" !V");break;case ICMP_UNREACH_PRECEDENCE_CUTOFF:++unreachable;printf(" !C");break;default:++unreachable;printf(" !<%d>", code);break;}break;}if (cc == 0) {loss++;printf(" *");}(void)fflush(stdout);}if (sump) {printf(" (%d%% loss)", (loss * 100) / t->nprobes);}putchar('\n');if (got_there ||(unreachable > 0 && unreachable >= t->nprobes - 1))break;}traceroute_free(t);exit(0);
}

在这里插入图片描述

ping 和 traceroute 有什么区别?

ping 和 traceroute 之间的主要区别在于,ping 只是告诉您服务器是否可访问以及传输和接收数据所需的时间,traceroute 详细说明了精确的路由,逐个路由器,以及每跳所花费的时间。

总结

本篇讲述了有关跟踪路由是什么、跟踪路由的工作原理、如何读取跟踪路由以及它们如何帮助解决网络问题的信息。

最后,traceroute 是网络诊断工具,用于判断网络上是否存在路由问题。 traceroute 可用于确定 IP 数据包从您的计算机到达远程计算机的路径。

欢迎关注微信公众号【程序猿编码】,需要traceroute完整源码的添加本人微信号(c17865354792)

参考:rfc791

这篇关于什么是traceroute?Linux C/C++下利用ICMP实现traceroute的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/742642

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor