nettools · 逐跳路径探测工具(ICMP/UDP/TCP)
Usage Guide — 并发探测多个 TTL 与多个目标,输出每跳 RTT 与丢包率;报文编解码全部基于 goscapy。
← 返回首页Probe ICMP/UDP/TCP Concurrent traceroute 是面向 IPv4 的逐跳路径探测工具,用于定位丢包/高时延发生在哪一跳、确认 ECMP 多路径下的实际转发路径。它支持 ICMP Echo、UDP、TCP SYN 三种探针,并发探测多个 TTL 与多个目标,无需服务端部署。
所有探测报文的构造与解析全部通过 smallnest/goscapy 完成,不存在手写的字节序或校验和逻辑。运行需要 raw socket,即 root / CAP_NET_RAW 权限。
traceroute 利用 IP 报文的 TTL(生存时间)字段:每经过一个路由器,TTL 减 1;当 TTL 减到 0 时,该路由器会丢弃报文并回送一个 ICMP Time Exceeded(类型 11)报文,其源 IP 就是这一跳的地址。
--queries 个探针;| 协议 | 探针 | 到达目标的判定 | 适用场景 |
|---|---|---|---|
icmp(默认) | ICMP Echo Request,id=pid、seq 编码 ttl/probe | 收到目标的 ICMP Echo Reply | 最通用 |
udp | UDP,目的端口随 TTL 递增(默认 33434 起) | 收到目标的 ICMP Port Unreachable | 传统 traceroute 行为,穿透性好 |
tcp | TCP SYN,固定目的端口(默认 80/443) | 收到目标的 SYN-ACK 或 RST | 穿越只放行特定 TCP 端口的防火墙 |
三者共用同一套「TTL 递增 + ICMP Time Exceeded 收集 + 多探针采样 + 逐跳统计」框架,仅探针发送与目标到达判定不同,用 --protocol 切换。
--src-port 固定源端口、--fixed-dport 固定 UDP 目的端口(默认按 TTL 递增)、--src-ip 伪造源 IP、--dst-ip 覆盖写入探针的目的 IP(独立于显示的目标),便于验证特定五元组/转发策略。这些选项对 ICMP 无效。源端口为 0 时按 (ttl,probe) 自动分配,保证并发探针可区分;固定源端口会牺牲源端口维度的区分(仍按内嵌头其余字段匹配)。--parallel(默认 16)限制在途探针总数,避免触发中间设备 ICMP 限速。每个探针通过 goscapy 的 Sr1 发送并等待首个匹配回包;匹配函数依据内嵌原始报文的标识字段(ICMP id/seq、UDP/TCP 端口)路由回包,确保并发下回包归属正确。
探针用 goscapy builder 构造,IP/ICMP/UDP/TCP 校验和自动计算:
// ICMP 探针,TTL 递增
ip := layers.NewIP()
ip.Set("src", srcIP); ip.Set("dst", dstIP); ip.Set("ttl", uint8(ttl))
icmp := layers.NewICMPEcho(pid, uint16(ttl)<<8|uint16(probe))
pkt := ip.Over(icmp)
// 回包解析(含 ICMP 错误内嵌的原始报文头)
resp, _ := packet.DissectByProto(raw, "IP")
icmpType, _ := resp.GetLayer("ICMP").Get("type")
编译:
go build -o traceroute ./cmd/traceroute/
# 或
make build-traceroute
运行(raw socket 需要 root / CAP_NET_RAW):
# ICMP traceroute(默认)
sudo ./traceroute example.com
# UDP traceroute,指定起始端口
sudo ./traceroute -p udp --port 33434 8.8.8.8
# TCP SYN traceroute 到 443 端口(适合穿越防火墙)
sudo ./traceroute -p tcp --port 443 example.com
# 一次并发探测多个目标
sudo ./traceroute 8.8.8.8 1.1.1.1 example.com
| 短 | 长 | 默认 | 说明 |
|---|---|---|---|
-p | --protocol | icmp | 探测协议:icmp / udp / tcp |
-m | --max-hops | 30 | 最大跳数(TTL) |
-q | --queries | 3 | 每跳探针数量 |
--port | 33434(udp)/80(tcp) | UDP/TCP 目标端口 | |
--src-port | 0 | UDP/TCP 源端口(0 = 按探针自动分配) | |
--fixed-dport | false | UDP 目标端口固定为 --port(不随 TTL 递增) | |
--src-ip | auto | 覆盖 UDP/TCP 探针源 IPv4(伪造源 IP) | |
--dst-ip | target | 覆盖写入 UDP/TCP 探针的目的 IPv4 | |
-w | --timeout | 1s | 单探针超时 |
--no-dns | false | 关闭反向 DNS 解析 | |
--asn | false | 经 Team Cymru DNS 为每跳标注起源 ASN / AS 名 / BGP 前缀(仅出站 DNS,无需 API key) | |
--geo | false | 经 ipinfo.io 为每跳标注归属地/运营商(会把每跳 IP 发往第三方) | |
--geo-token | 空 | ipinfo.io API token(可选;为空则用匿名额度) | |
-t | --tos | 0 | IP TOS/DSCP 值 |
--parallel | 16 | 并发在途探针上限 | |
-I | --interface | auto | 出向网卡(自动探测) |
-l | --local-addr | auto | 本地源 IPv4(自动探测) |
-V | --version | false | 打印版本并退出 |
输出风格对齐传统 traceroute / aeden/traceroute,每跳一行,附带各探针 RTT;无响应的探针显示为 *,ECMP 同 TTL 多个回源就地展示。
traceroute to example.com (93.184.216.34), 30 hops max, ICMP probes, 60 byte packets
1 gateway (192.168.1.1) 1.234ms 1.301ms 1.122ms
2 10.0.0.1 (10.0.0.1) 5.678ms 5.521ms *
3 * * *
4 core1.isp.net (203.0.113.5) 12.345ms 12.201ms 12.503ms
可选地为每跳 IP 附加 ASN / AS 名 / BGP 前缀与地理归属地信息,类似 NextTrace 的可视化效果。数据来源做成可插拔的 Provider 接口(traceroute/enrich 包),默认两种实现,未来可替换为离线 MaxMind、bgp.tools、内部服务等。
| 开关 | 数据源 | 提供字段 | 依赖 |
|---|---|---|---|
--asn | Team Cymru IP-to-ASN DNS | 起源 ASN、AS 名、覆盖 BGP 前缀 | 仅出站 DNS,无需 API key |
--geo | ipinfo.io HTTP API | 国家、省/州、城市、运营商 | 需访问外网,可选 --geo-token |
两者均默认关闭,不开启时行为与原版完全一致。查询在所有探测完成后统一并发执行,并按 IP 去重(同一 ASN 的 AS 名也会缓存),不影响探测路径本身。
--geo 会把每个命中跳的 IP 发送给第三方(ipinfo.io)。在敏感网络环境中请优先只用 --asn(纯 DNS),或接入离线数据源。# 标注 ASN / BGP 前缀(纯 DNS)
sudo ./traceroute --asn 8.8.8.8
# 同时标注归属地(带 token 提升额度)
sudo ./traceroute --asn --geo --geo-token <your-token> example.com
输出会在每跳行尾追加方括号注释,格式 [ASN AS名 前缀 | 国家 省 城市]:
traceroute to dns.google (8.8.8.8), 30 hops max, ICMP probes, 60 byte packets
1 gateway (192.168.1.1) 1.234ms 1.301ms 1.122ms
2 core1.isp.net (203.0.113.5) [AS4134 CHINANET-BACKBONE 203.0.113.0/24 | CN Beijing] 12.3ms 12.2ms
3 dns.google (8.8.8.8) [AS15169 GOOGLE 8.8.8.0/24 | US Mountain View] 30.1ms 29.8ms
--port 443)或 UDP 探针穿越对 ICMP 限速/过滤的网络。为什么需要 root? 构造自定义 IP/ICMP/UDP/TCP 报文并设置 TTL 需要 raw socket,需 root 或 CAP_NET_RAW(sudo setcap cap_net_raw+ep ./traceroute)。
支持 IPv6 吗? 当前实现优先 IPv4;包结构预留了 IPv6(HopLimit)扩展,与 ping/ping6 的双栈风格保持一致。
某些跳一直是 *? 该跳路由器可能对 ICMP Time Exceeded 限速或不回送,属正常现象,不一定代表丢包。