#ping #tcp #networking #utility #tcpping

bin+lib rnp

云服务的简单第四层 ping 工具

23 个版本

0.1.146 2022年9月10日
0.1.143 2022年3月14日
0.1.141 2021年11月14日
0.1.115 2021年8月9日
0.1.108 2021年7月26日

#967 in 网络编程

Apache-2.0

265KB
4K SLoC

Rnp - 云服务的简单第四层 ping 工具。

Rnp

Documentation Build Status codecov License: Apache 2.0

发布 状态
Crates.io Crates.io
安装 GitHub release (latest SemVer) Chocolatey Version winget apt/deb
Nuget
Nuget Nuget Nuget
Nuget Nuget Nuget Nuget
Nuget
$ rnp 8.8.8.8:443 -r -l
rnp - r12f (r12f.com, github.com/r12f) - A simple layer 4 ping tool for cloud.

Start testing TCP 8.8.8.8:443:
Reaching TCP 8.8.8.8:443 from 192.168.50.153:8940 succeeded: RTT=12.95ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:8941 succeeded: RTT=11.24ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:8942 succeeded: RTT=10.96ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:8943 succeeded: RTT=12.43ms

=== TCP connect statistics for 8.8.8.8:443 ===
- Packets: Sent = 4, Received = 4, Lost = 0 (0.00% loss).
- Round trip time: Minimum = 10.96ms, Maximum = 12.95ms, Average = 11.90ms.

=== Ping result scatter map ===

    Src | Results
   Port | ("1" = Ok, "0" = Fail, "-" = Not Tested)
--------+-0---4-5---9-0---4-5---9-------------------
   8940 | 1111- ----- ----- -----

=== Latency scatter map (in milliseconds) ===

  Src Port | Results ("X" = Fail, "-" = Not Tested)
-----------+----0------1------2------3------4------5------6------7------8------9---
      8940 |  12.95  11.24  10.96  12.43    -      -      -      -      -      -

安装

我们目前支持多种安装 Rnp 的方式。请在此处查看详细文档:如何安装

为什么选择 Rnp?

Ping 是最常用于测试网络可达性的工具之一。然而,这里我们还有另一个选择... 为什么呢?

尽管市场上有很多 ping 工具,但我编写 Rnp 有以下几个具体原因

  • 广泛平台支持,因此我们可以在任何地方运行它。
    • 广泛平台支持:Windows/Linux,x86/amd64/arm64。
    • 广泛机器环境支持:最小依赖,例如运行时如 JRE/CLR。
  • 云友好:
    • 支持扫描所有网络路径。
      • 如今,服务和网络数据路径大多冗余。负载均衡器和 ECMP 等技术广泛应用于云和现代数据中心。
      • 因此,如果服务或网络链路出现问题,我们会看到中间数据包丢失/延迟,而不是看到全连接丢失。因此,我们需要一个工具来帮助我们扫描所有可能的路由并找到不良链路。
    • 最小化对现有数据路径的影响,例如高端口使用和网络堆栈负载。
      • 高端口使用会导致您的机器用尽可用源端口,从而导致您的服务在创建新连接时失败。这可以通过网络测试/扫描轻松触发。
      • 当您检查网络连接到互联网时,这会更糟,因为出站端口还需要在您的负载均衡器上进行分配,这是跨所有机器共享的。这是所有云中一个非常常见的错误,例如 AWSAzure
  • 尽可能避免不稳定的测量。
  • 易于使用。
  • ...

为了帮助我们实现上述目标,我们以非常具体的方式实现我们的 ping。

  • 将 TCP 连接用作 ping。 专注于网络可达性。
    • 为什么不使用 ICMP ping?
      1. 与 TCP 不同,ICMP 缺乏变体,这使得它不适合扫描所有可能的路由。
      2. 由于安全原因,许多机器和网络禁用了ICMP,所以ICMP超时并不真正意味着超时。
    • 为什么不是UDP ping呢?
      1. UDP是无连接的,所以没有所谓的UDP ping。
      2. 现有的UDP ping工具使用ICMP不可达消息来检测UDP端口是否可达,这导致了2个问题
        1. 实现通常涉及使用原始套接字,这会对性能产生负面影响,尤其是在网络负载可能很高的云环境中。
        2. 与ICMP ping相同。ICMP可能被禁用,因此UDP ping工作并不真正意味着UDP端口开放。(禁止ICMP的一个原因是为了避免这种UDP端口扫描。)
  • 并行ping以喷洒所有可能的网络路径
    • 我们旋转源端口,使每个ping具有不同的元组,以便它们可以通过不同的网络路径。
    • 具有可配置ping间隔的并行ping可以显著提高扫描速度。
  • 默认使用RST而不是FIN以最小化端口使用。
    • 大多数tcp连接工具都遵循常规方式断开TCP连接 - 使用FIN数据包的四路握手。这对服务器很好,但对测试来说却不是这样。
    • 常规断开连接将端口留在TIME_WAIT状态,云负载均衡器必须跟踪这些SNAT端口。这很容易导致SNAT端口分配错误,从而使您的服务网络变得更糟。您绝对不希望看到这种情况。
  • 不使用原始套接字
    • 许多ping工具使用原始套接字来实现ping,允许您操纵数据包或支持混合协议ping,如UDP ping。这些功能在某些情况下很有帮助,但对大多数人来说并不真正需要。
    • 原始套接字会导致内核将所有匹配您绑定到套接字上的IP的数据包都交付。当负载很高时,这会给网络栈带来巨大的负担,因此我们避免使用它。
  • 使用Rust作为编程语言
    • Rust是一种轻量级的系统语言,具有无GC的运行时,这意味着在我们的测量过程中不再会有随机延迟,如GC中的停止世界阶段。
    • Rust具有广泛的平台支持,并生成几乎自包含的本机二进制文件,因此我们可以简单地复制并运行。
    • Rust与C一样快,同时还有对现代异步编程的出色支持。例如,像go-like mpsc channel、async/await这样的功能,你都可以在Rust中找到。
    • ...
  • 友好的结果输出:
    • 除了像ping一样输出之外,我们还提供了其他显示结果的方式,例如非常紧凑的散点图。
    • 我们还支持将结果输出到CSV/JSON/Text文件,供以后分析或脚本使用。

一些艰难的决定

  • 有意不支持DNS名称解析。使用我们的ping时,强制使用IP地址。
    • 这是因为DNS可以根据地理位置返回不同的结果。当协作处理网络问题时,这会导致很多人长时间内都在调试不同的问题,甚至不知道。
    • 要从DNS获取IP,我们可以运行nslookup <domain-name>

用法

好的,让我们检查一些实际案例以开始!

最简单的情况 - 常规TCP连接测试。就像ping一样工作。

rnp 8.8.8.8:443
rnp - r12f (r12f.com, github.com/r12f) - A simple layer 4 ping tool for cloud.

Start testing TCP 8.8.8.8:443:
Reaching TCP 8.8.8.8:443 from 192.168.50.153:10401 succeeded: RTT=11.17ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:10402 succeeded: RTT=13.36ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:10403 succeeded: RTT=14.27ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:10404 succeeded: RTT=12.39ms

=== TCP connect statistics for 8.8.8.8:443 ===
- Packets: Sent = 4, Received = 4, Lost = 0 (0.00% loss).
- Round trip time: Minimum = 11.17ms, Maximum = 14.27ms, Average = 12.80ms.

现在让我们通过添加 -p 10 来加速我们的ping,以启动10个工作进程,并添加 -i 0 来删除每个ping之间的间隔,然后运行100次ping。为了避免滥用我们的控制台,我们禁用常规输出(-q),启用结果散点图(-r),并将详细信息记录到json文件中以便以后使用(--log-json log.json)。

$ rnp.exe 8.8.8.8:443 -p 10 -i 0 -n 100 -q -r --log-json log.json
rnp - r12f (r12f.com, github.com/r12f) - A simple layer 4 ping tool for cloud.

Start testing TCP 8.8.8.8:443:
97 pings finished.
=== TCP connect statistics for 8.8.8.8:443 ===
- Packets: Sent = 100, Received = 96, Lost = 4 (4.00% loss).
- Round trip time: Minimum = 10.91ms, Maximum = 999.43ms, Average = 55.16ms.

=== Ping result scatter map ===

    Src | Results
   Port | ("1" = Ok, "0" = Fail, "-" = Not Tested)
--------+-0---4-5---9-0---4-5---9-------------------
  18180 | ----- ----1 11111 11111
  18200 | 11111 11111 11111 11111
  18220 | 11111 11111 11111 11111
  18240 | 11111 11111 11111 11111
  18260 | 11111 11111 11111 11111
  18280 | 10000 1111- ----- -----

我们将看到测试几乎立即完成,并且详细信息将被记录到json文件中。

[
  {"utcTime":"2021-07-09T04:54:50.465178Z","protocol":"TCP","workerId":4,"targetIP":"8.8.8.8","targetPort":"443","sourceIP":"192.168.50.153","sourcePort":"18285","roundTripTimeInMs":17.14,"error":""},
  {"utcTime":"2021-07-09T04:54:50.465430300Z","protocol":"TCP","workerId":8,"targetIP":"8.8.8.8","targetPort":"443","sourceIP":"192.168.50.153","sourcePort":"18288","roundTripTimeInMs":23.25,"error":""},
  {"utcTime":"2021-07-09T04:54:50.458698800Z","protocol":"TCP","workerId":6,"targetIP":"8.8.8.8","targetPort":"443","sourceIP":"0.0.0.0","sourcePort":"18282","roundTripTimeInMs":998.91,"error":"timed out"},
]

现在,我们可以看到我们的ping在端口19653上失败,然后我们可以开始连续ping来重新运行失败的端口。我们可以看到这个端口的失败率相当高,如下所示。

$ rnp.exe 8.8.8.8:443 --src-port 18282 -t
rnp - r12f (r12f.com, github.com/r12f) - A simple layer 4 ping tool for cloud.

Start testing TCP 8.8.8.8:443:
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18282 succeeded: RTT=11.65ms
Reaching TCP 8.8.8.8:443 from 0.0.0.0:18282 failed: Timed out, RTT = 999.24ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18282 succeeded: RTT=12.24ms
.....

此外,我们可以轻松尝试所有失败端口,并查看它们的状况。以下是一个使用powershell的示例,在非Windows平台上,我们可以使用类似jq的工具轻松完成相同的事情。

# Extract the failure ports
$ $ports = (gc .\log.json | ConvertFrom-Json | % { $_ } | ? { $_.error -eq "timed out" } | % { $_.sourcePort }) -join ","
$ $ports
18282,18281,18284,18283

# Retry
$ rnp.exe 8.8.8.8:443 --src-ports $ports -t
rnp - r12f (r12f.com, github.com/r12f) - A simple layer 4 ping tool for cloud.

Start testing TCP 8.8.8.8:443:
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18284 succeeded: RTT=11.24ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18283 succeeded: RTT=11.15ms
Reaching TCP 8.8.8.8:443 from 0.0.0.0:18282 failed: Timed out, RTT = 999.14ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18281 succeeded: RTT=11.53ms
Reaching TCP 8.8.8.8:443 from 0.0.0.0:18284 failed: Timed out, RTT = 999.50ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18283 succeeded: RTT=11.88ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18282 succeeded: RTT=10.90ms
Reaching TCP 8.8.8.8:443 from 0.0.0.0:18281 failed: Timed out, RTT = 999.38ms
Reaching TCP 8.8.8.8:443 from 192.168.50.153:18284 succeeded: RTT=14.40ms
.....

rnp将开始对所有指定的源端口进行ping轮询测试。

更多帮助信息

要了解更多关于此工具的信息,我们可以尝试使用--help选项。

$ rnp.exe --help
rnp 0.1.114
r12f (r12f.com, github.com/r12f)
A simple layer 4 ping tool for cloud.

USAGE:
    rnp [FLAGS] [OPTIONS] <target>

FLAGS:
    -d, --check-disconnect        Check if connection can be correctly disconnected. Only available in TCP mode now.
                                  When enabled, we will use normal disconnect (w/ FIN) and check the connection
                                  disconnect.
    -h, --help                    Prints help information
        --log-tls-key             Enable key logger in TLS for helping packet capture.
                                  Please note that it might cause RTT to be slightly larger than the real one, because
                                  logging key will also take time.
    -q, --no-console-log          Don't log each ping result to console. Summary and other things will still be written
                                  to console.
    -t                            Ping until stopped.
    -l, --show-latency-scatter    Show latency (round trip time) scatter map after ping is done.
    -r, --show-result-scatter     Show ping result scatter map after ping is done.
        --use-timer-rtt           Calculate the RTT by checking the time of before and after doing QUIC connect instead
                                  of estimated RTT from QUIC. Not recommended, as this might cause the RTT time to be
                                  larger than the real one.
    -V, --version                 Prints version information

OPTIONS:
        --alpn <alpn-protocol>
            ALPN protocol used in QUIC. Specify "none" to disable ALPN.
            It is usually h3-<ver> for http/3 or hq-<ver> for specific version of QUIC.
            For latest IDs, please check here: https://www.iana.org/assignments/tls-extensiontype-values/tls-
            extensiontype-values.xhtml#alpn-protocol-ids
            [default: h3-29]
        --log-csv <csv-log-path>                  Log ping results a csv file. [alias: --oc]
        --log-json <json-log-path>                Log ping results to a json file. [alias: --oj]
    -b, --latency-buckets <latency-buckets>...
            If set, bucket ping latency (round trip time) after ping is done. Set to 0.0 to use the default one:
            [0.1,0.5,1.0,10.0,50.0,100.0,300.0,500.0]
    -p, --parallel <parallel-ping-count>          Count of pings running in parallel. [default: 1]
    -n, --count <ping-count>                      Ping count. [default: 4]
    -i, --interval <ping-interval-in-ms>          Sleep between each ping in milliseconds. [default: 1000]
    -m, --mode <protocol>                         Specify protocol to use. [default: TCP]
        --server-name <server-name>               Specify the server name in the QUIC pings. Example: localhost.
    -s, --src-ip <source-ip>                      Source IP address. [default: 0.0.0.0]
        --src-ports <source-ports>
            Source port ranges to rotate in ping. Format: port,start-end. Example: 1024,10000-11000. [alias: --sp]

    -o, --log-text <text-log-path>                Log ping results to a text file.
        --ttl <time-to-live>                      Time to live.
    -w, --timeout <wait-timeout-in-ms>            Wait time for each ping in milliseconds. [default: 2000]
        --warmup <warmup-count>                   Warm up ping count. [default: 0]

ARGS:
    <target>

贡献

非常感谢您对这个项目的兴趣,所有贡献都受到欢迎!

要贡献力量,请遵循我们的如何贡献文档。

资源

许可

Apache-2.0: https://apache.ac.cn/licenses/LICENSE-2.0

依赖项

~21–34MB
~614K SLoC