【Shell 命令集合 网络通讯 】Linux 追踪数据包在网络中的路径 traceroute命令 使用指南

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: 【Shell 命令集合 网络通讯 】Linux 追踪数据包在网络中的路径 traceroute命令 使用指南

描述


traceroute命令用于追踪数据包在网络中的路径。它通过发送一系列的ICMP(Internet Control Message Protocol)回显请求数据包(ping包),并记录每个数据包的传输时间,从而确定数据包从源主机到目标主机经过的所有中间路由器。

当我们使用traceroute命令时,它会发送一系列的数据包,每个数据包的TTL(生存时间)值逐渐递增。当数据包到达某个中间路由器时,如果TTL值为0,路由器会将该数据包丢弃,并发送一个ICMP回显超时消息给源主机。通过这种方式,traceroute命令可以获取数据包经过的每个中间路由器的IP地址和传输时间。

通过分析traceroute命令的输出,我们可以确定数据包在网络中的路径,以及每个中间路由器的响应时间。这对于网络故障排除和网络性能优化非常有帮助。我们可以根据traceroute的结果,确定数据包在网络中的瓶颈位置,并采取相应的措施来改善网络性能。

总结起来,traceroute命令的作用是通过发送一系列的ICMP回显请求数据包,追踪数据包在网络中的路径,并记录每个数据包的传输时间,以便分析网络性能和故障排除。


语法格式

traceroute [选项] 目标主机

参数说明

  • -n:以数字形式显示中间路由器的IP地址,而不进行反向DNS查找。
  • -q <次数>:设置每个TTL值发送的数据包数量。
  • -I:使用ICMP Echo请求数据包(ping包)进行追踪,而不是默认的UDP数据包。
  • -w <超时时间>:设置等待每个中间路由器响应的超时时间。
  • -m <最大跳数>:设置追踪路径的最大长度,即最大跳数。
  • -f <起始TTL值>:设置起始TTL值,即从指定跳数开始追踪路径。

错误情况

  • 如果目标主机无法到达或不存在,traceroute命令将显示相关错误信息,如"无法解析主机"或"网络不可达"。
  • 如果网络中存在防火墙或路由器配置问题,可能会导致traceroute命令失败或无法显示完整的路径。
  • 如果traceroute命令的超时时间设置过短,可能会导致中间路由器无法及时响应,从而显示超时错误。

请注意,以上是一些常见的错误情况,实际情况可能因网络配置和环境而有所不同。在使用traceroute命令时,需要根据具体情况进行参数设置和错误排查。

注意事项

在使用Linux Shell中的traceroute命令时,有一些注意事项需要考虑:

  1. 需要使用管理员权限:traceroute命令需要发送和接收ICMP或UDP数据包,这通常需要管理员权限。因此,在使用traceroute命令之前,请确保您具有足够的权限,或者使用sudo来执行命令。
  2. 防火墙和路由器配置:在某些情况下,网络中的防火墙或路由器配置可能会阻止或限制traceroute命令的正常执行。如果您发现无法获取完整的路径或出现超时错误,请检查网络设备的配置,并确保允许ICMP或UDP数据包通过。
  3. 解析主机名的延迟:traceroute命令默认会尝试解析每个中间路由器的IP地址对应的主机名。这可能会导致一些延迟,特别是在网络中存在DNS问题或主机名解析较慢的情况下。如果您对延迟比较敏感,可以使用-n选项来禁用主机名解析。
  4. 超时时间的设置:traceroute命令会等待每个中间路由器的响应,如果超过了设定的超时时间仍未收到响应,将显示超时错误。默认的超时时间可能不适用于所有网络环境。您可以使用-w选项来设置合适的超时时间,以确保能够获取到足够的响应。
  5. 最大跳数的设置:traceroute命令默认的最大跳数为30,这意味着如果数据包在30个跳内未到达目标主机,将停止追踪并显示相关信息。在某些网络中,可能需要设置更大的最大跳数,以便追踪更长的路径。您可以使用-m选项来设置最大跳数。
  6. 安全性考虑:由于traceroute命令涉及发送和接收网络数据包,可能会引起一些安全问题。在某些情况下,网络管理员可能会限制或禁止使用traceroute命令。在使用traceroute命令时,请确保您已获得适当的授权,并遵守相关的安全政策和规定。

总之,在使用traceroute命令时,请确保您具备足够的权限、了解网络环境和配置,并注意安全性和延迟等因素。


底层实现

在Linux Shell中,traceroute命令的底层实现是通过发送特定类型的网络数据包来追踪路径。具体来说,它使用了ICMP(Internet Control Message Protocol)或UDP(User Datagram Protocol)数据包来实现。

当我们执行traceroute命令时,它会创建一个原始套接字(raw socket)来发送数据包。在每个数据包中,它会设置一个特定的TTL(Time to Live)值,该值指定了数据包在网络中可以经过的最大跳数。初始TTL值通常为1。

traceroute命令通过发送数据包到目标主机,并等待每个中间路由器的响应。如果一个中间路由器收到了数据包,但发现TTL值已经为0,它会丢弃该数据包,并发送一个ICMP超时消息(如果使用ICMP协议)或UDP端口不可达消息(如果使用UDP协议)给源主机。这样,traceroute命令就能够确定数据包经过的每个中间路由器的IP地址和传输时间。

为了获取更多的信息,traceroute命令会逐渐增加TTL值,并发送多个数据包,以便覆盖整个路径。它会记录每个数据包的传输时间和路由器的IP地址,然后将结果输出给用户。

需要注意的是,底层实现可能因操作系统和网络设备的不同而有所差异。不同的操作系统可能使用不同的方式来发送和接收数据包,而网络设备的配置和策略也可能会影响traceroute命令的执行和结果。

总结起来,traceroute命令底层通过发送特定类型的网络数据包(ICMP或UDP)来追踪路径。它使用TTL值来控制数据包在网络中经过的跳数,并通过接收中间路由器的响应来确定路径和传输时间。


示例

示例一

$ traceroute www.google.com

该命令将追踪到达www.google.com的路径,并显示每个中间路由器的IP地址和传输时间。

示例二

$ traceroute -n 192.168.0.1

该命令将以数字形式显示中间路由器的IP地址,而不进行反向DNS查找。

示例三

$ traceroute -q 10 www.example.com

该命令将发送10个数据包来追踪到达www.example.com的路径。

示例四

$ traceroute -I 8.8.8.8

该命令将使用ICMP Echo请求数据包(ping包)进行追踪,而不是默认的UDP数据包。

示例五

$ traceroute -w 2 www.yahoo.com

该命令将设置等待每个中间路由器响应的超时时间为2秒。

示例六

$ traceroute -m 20 www.microsoft.com

该命令将设置最大跳数为20,即追踪路径的最大长度为20跳。

示例七

$ traceroute -f 5 www.amazon.com

该命令将设置起始TTL值为5,即从第5跳开始追踪路径。


用c语言实现


下面是一个使用C语言实现traceroute命令的简单示例代码,代码中使用了原始套接字(raw socket)来发送和接收网络数据包。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAX_HOPS 30
#define PACKET_SIZE 64
#define ICMP_ECHO_REQUEST 8
#define ICMP_ECHO_REPLY 0
#define ICMP_TIME_EXCEEDED 11
// 计算校验和
unsigned short calculateChecksum(unsigned short *buffer, int length) {
    unsigned long sum = 0;
    while (length > 1) {
        sum += *buffer++;
        length -= 2;
    }
    if (length == 1) {
        sum += *(unsigned char *)buffer;
    }
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    return ~sum;
}
// 发送ICMP回显请求数据包
void sendEchoRequest(int sockfd, struct sockaddr_in *dest_addr, int ttl) {
    struct icmphdr icmp_header;
    memset(&icmp_header, 0, sizeof(struct icmphdr));
    icmp_header.type = ICMP_ECHO_REQUEST;
    icmp_header.code = 0;
    icmp_header.un.echo.id = getpid();
    icmp_header.un.echo.sequence = ttl;
    icmp_header.checksum = calculateChecksum((unsigned short *)&icmp_header, sizeof(struct icmphdr));
    setsockopt(sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(int));
    sendto(sockfd, &icmp_header, sizeof(struct icmphdr), 0, (struct sockaddr *)dest_addr, sizeof(struct sockaddr_in));
}
// 接收ICMP回显回复数据包
int receiveEchoReply(int sockfd, int ttl, struct sockaddr_in *recv_addr, float *rtt) {
    char buffer[PACKET_SIZE];
    struct timeval start_time, end_time;
    socklen_t addr_len = sizeof(struct sockaddr_in);
    gettimeofday(&start_time, NULL);
    ssize_t bytes_received = recvfrom(sockfd, buffer, PACKET_SIZE, 0, (struct sockaddr *)recv_addr, &addr_len);
    gettimeofday(&end_time, NULL);
    *rtt = (end_time.tv_sec - start_time.tv_sec) * 1000.0 + (end_time.tv_usec - start_time.tv_usec) / 1000.0;
    if (bytes_received >= sizeof(struct iphdr) + sizeof(struct icmphdr)) {
        struct iphdr *ip_header = (struct iphdr *)buffer;
        struct icmphdr *icmp_header = (struct icmphdr *)(buffer + (ip_header->ihl * 4));
        if (icmp_header->type == ICMP_ECHO_REPLY) {
            return 1; // 收到回复
        } else if (icmp_header->type == ICMP_TIME_EXCEEDED) {
            return 2; // TTL超时
        }
    }
    return 0; // 其他情况
}
int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <destination>\n", argv[0]);
        return 1;
    }
    struct hostent *host = gethostbyname(argv[1]);
    if (host == NULL) {
        printf("Cannot resolve hostname.\n");
        return 1;
    }
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        perror("Socket creation failed");
        return 1;
    }
    struct sockaddr_in dest_addr;
    memset(&dest_addr, 0, sizeof(struct sockaddr_in));
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_addr = *((struct in_addr *)host->h_addr);
    printf("Traceroute to %s (%s)\n", argv[1], inet_ntoa(dest_addr.sin_addr));
    for (int ttl = 1; ttl <= MAX_HOPS; ttl++) {
        printf("%2d ", ttl);
        for (int i = 0; i < 3; i++) {
            sendEchoRequest(sockfd, &dest_addr, ttl);
            struct sockaddr_in recv_addr;
            memset(&recv_addr, 0, sizeof(struct sockaddr_in));
            float rtt = 0.0;
            int result = receiveEchoReply(sockfd, ttl, &recv_addr, &rtt);
            if (result == 1) {
                printf(" %.3f ms", rtt);
                break;
            } else if (result == 2) {
                printf(" *");
            } else {
                printf(" ???");
            }
        }
        printf("\n");
    }
    close(sockfd);
    return 0;
}

这段代码使用了原始套接字(raw socket)来发送和接收ICMP数据包。它通过设置TTL值和发送ICMP回显请求数据包来追踪路径,并通过接收ICMP回显回复数据包来获取每个中间路由器的响应时间。代码中还包含了一些辅助函数,如计算校验和和处理时间等。

请注意,使用原始套接字需要具有管理员权限。因此,在运行该代码时,您可能需要使用sudo或以root用户身份执行。此外,由于使用了原始套接字,该代码只能在Linux等支持原始套接字的操作系统上运行。

这只是一个简单的示例,实际上,traceroute命令的实现要更加复杂,涉及到更多的选项和错误处理。此外,由于网络环境的不同,代码可能需要进行适当的调整和修改。


结语

在我们的探索过程中,我们已经深入了解了Shell命令的强大功能和广泛应用。然而,学习这些技术只是开始。真正的力量来自于你如何将它们融入到你的日常工作中,以提高效率和生产力。

心理学告诉我们,学习是一个持续且积极参与的过程。所以,我鼓励你不仅要阅读和理解这些命令,还要动手实践它们。尝试创建自己的命令,逐步掌握Shell编程,使其成为你日常工作的一部分。

同时,请记住分享是学习过程中非常重要的一环。如果你发现本博客对你有帮助,请不吝点赞并留下评论。分享你自己在使用Shell命令时遇到的问题或者有趣的经验,可以帮助更多人从中学习。

此外,我也欢迎你收藏本博客,并随时回来查阅。因为复习和反复实践也是巩固知识、提高技能的关键。

最后,请记住:每个人都可以通过持续学习和实践成为Shell编程专家。我期待看到你在这个旅途中取得更大进步!

目录
相关文章
|
9天前
|
安全 网络安全 网络架构
掌握traceroute:网络工程师解决路由问题的利器
【8月更文挑战第22天】`traceroute`是网络工程师的关键工具,用于追踪数据包从源到目的地的路径,帮助诊断网络问题并优化性能。通过向目标发送具有特定生存时间(TTL)值的数据包,`traceroute`能揭示每跳路由器的信息及延迟,便于识别瓶颈与故障。其基本用法为`traceroute [options] hostname/IP`。
29 1
|
2天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
8天前
|
存储 Linux Shell
在Linux中,如何使用脚本,实现判断 192.168.1.0/24 网络里,当前在线的 IP 有哪些?能ping 通则 认为在线。
在Linux中,如何使用脚本,实现判断 192.168.1.0/24 网络里,当前在线的 IP 有哪些?能ping 通则 认为在线。
|
8天前
|
监控 网络协议 Linux
在Linux中,如何实时抓取并显示当前系统中tcp 80 端口的网络数据信息?
在Linux中,如何实时抓取并显示当前系统中tcp 80 端口的网络数据信息?
|
9天前
|
运维 监控 网络协议
在Linux中,如何进行网络故障排查?
在Linux中,如何进行网络故障排查?
|
10天前
|
Prometheus 监控 网络协议
在Linux中,如何监控网络服务的状态和性能?
在Linux中,如何监控网络服务的状态和性能?
|
9天前
|
存储 Ubuntu Linux
揭开自制NAS的神秘面纱:一步步教你如何用Linux打造专属网络存储王国!
【8月更文挑战第22天】构建Linux NAS系统是技术爱好者的热门项目。通过选择合适的发行版如Alpine Linux或Ubuntu Server,并利用现有硬件,你可以创建一个高效、可定制的存储解决方案。安装Linux后,配置网络设置确保可达性,接着安装Samba或NFS实现文件共享。设置SSH服务方便远程管理,利用`rsync`与`cron`进行定期备份。还可添加Web界面如Nextcloud提升用户体验。这一过程不仅节约成本,还赋予用户高度的灵活性和控制权。随着技术发展,Linux NAS方案持续进化,为用户带来更丰富的功能和可能性。
22 1
|
10天前
|
存储 运维 安全
在Linux中,如何使用tcpdump和tshark进行实时数据包捕获?
在Linux中,如何使用tcpdump和tshark进行实时数据包捕获?
|
7天前
|
存储 Linux 网络安全
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
|
7天前
|
存储 Linux 网络安全
【Azure 应用服务】App Service For Linux 如何在 Web 应用实例上住抓取网络日志
【Azure 应用服务】App Service For Linux 如何在 Web 应用实例上住抓取网络日志
下一篇
云函数