如何测量与远程计算机的特定 SSH 连接的带宽?例如,如果我有一个 SSH 隧道进行端口转发,我想知道有多少数据通过该隧道。特别是,我想知道两个方向的传输速度以及传输的总数据量(两个方向分别)。我怎样才能做到这一点?
操作系统:Debian 11 和 Ubuntu 20.04。
答案1
您可以测量通过 ssh 连接发送的网络流量。
例如:
iftop -i "$iface" -nPf "tcp and port $sport and port $dport"
ssh 连接的数据包将在哪个$iface
接口上发送/接收,以及$sport
/$dport
源和目标 TCP 端口。您还可以f
通过指定源 IP 地址和目标 IP 地址来进一步细化过滤器。
或者使用nethogs "$iface"
它会给你每个进程的细分。
但这些确实包括以太网、IP、TCP 和 ssh 协议增加的开销,因此不包括加密前通过 ssh 隧道的数据量。
tshark
您可以通过解码数据包并告诉您 TCP 有效负载的大小来消除以太网、IP、TCP 开销。但它无法进一步剖析 ssh 协议,因为它是加密的。
为了从不同的渠道处理多少数据ssh
,我们需要ssh
告诉我们自己。或者,我们可以用来报告进程进行的strace
每个read()
s 和s 系统调用。对 ssh TCP 套接字的读/写将告诉我们在加密和 ssh 协议开销之后发送了多少数据(应与上面的 TCP 有效负载匹配),而其余大部分应该是它在不同通道上读写的数据(例如用于交互式会话的 tty、用于端口重定向的网络套接字等)。write()
ssh
作为概念证明,可以使用 Perl 脚本来完成,例如:
#! /usr/bin/perl
# usage: that-script <pid-of-ssh>
my $pid = shift@ARGV;
my $tunnel_fd;
# list the fds of the process on TCP sockets
open my $lsof, '-|', qw(lsof -wnPa -i tcp -Fd -p), $pid;
while (<$lsof>) {
if (/^f(\d+)/) {
# the first fd on a TCP socket is assumed to be that of the ssh connection
$tunnel_fd = $1;
last;
}
}
close $lsof;
die "can't identify tunnel fd\n" unless defined $tunnel_fd;
my %dir;
sub pv {
open my $fh, '|-', "sh", "-c", q(exec pv "-ctrabN$0" 2>&1 > /dev/null), $_[0];
$fh->autoflush(1);
return $fh;
}
open my $strace, '-|', qw(strace -q -s0 -e trace=read,write -e status=successful -a0 -o/dev/stdout -p), $pid;
$dir{"1read"} = pv "outer IN";
$dir{"write"} = pv "inner IN";
$dir{"read"} = pv "inner OUT";
$dir{"1write"} = pv "outer OUT";
while (<$strace>) {
if (/^(read|write)\((\d+).*= (\d+)/) {
print { $dir{($2 eq $tunnel_fd) . $1} } "." x $3;
}
}
这里用于pv
报告b
时间、经过的t
时间、即时r
进食和a
平均速率。
给予类似的东西:
$ sudo ./ssh-stat 26655
outer IN: 768KiB 0:00:55 [0.00 B/s] [14.0KiB/s]
inner IN: 718KiB 0:00:55 [0.00 B/s] [13.1KiB/s]
inner OUT: 33.0 B 0:00:55 [0.00 B/s] [ 613miB/s]
outer OUT: 1.62KiB 0:00:55 [0.00 B/s] [30.2 B/s]
例如,这里的 33 个字节inner OUT
是与我在终端上键入的键相对应发送的几个字符,而outer OUT
是作为 ssh 协议的一部分发送的数据(以封装这些字符,但我也想确认在其他方向)。
要获得每个 ssh 通道的详细信息,您可以对其进行扩展,为每个 fd 提供单独的报告。其中描述每个 fd-yy
的选项可以提供帮助。strace
例如:
$ sudo strace -yy -q -s0 -e trace=read,write -e status=successful -a0 -o /dev/stdout -p 26655
read(6</dev/pts/1<char 136:1>>, ""..., 16384) = 3
write(3<TCP:[127.0.0.1:42334->127.0.0.1:22]>, ""..., 44) = 44
read(3<TCP:[127.0.0.1:42334->127.0.0.1:22]>, ""..., 8192) = 52
write(7</dev/pts/1<char 136:1>>, ""..., 16) = 16
read(6</dev/pts/1<char 136:1>>, ""..., 16384) = 3
write(3<TCP:[127.0.0.1:42334->127.0.0.1:22]>, ""..., 44) = 44
read(3<TCP:[127.0.0.1:42334->127.0.0.1:22]>, ""..., 8192) = 60
write(7</dev/pts/1<char 136:1>>, ""..., 26) = 26
read(3<TCP:[127.0.0.1:42334->127.0.0.1:22]>, ""..., 8192) = 44
write(9<TCP:[127.0.0.1:12344->127.0.0.1:43144]>, ""..., 3) = 3
read(9<TCP:[127.0.0.1:12344->127.0.0.1:43144]>, ""..., 16384) = 11
write(3<TCP:[127.0.0.1:42334->127.0.0.1:22]>, ""..., 52) = 52
在我的测试中显示了 ssh 连接上有多少数据 (fd 3)、从/到 tty (fds 6, 7) 的数据量、从本地端口转发到端口 12344 的数据量 (fd 9) 。