Speedtest всем хорош, кроме того что он позволяет измерить скорость от “себя” до некоего рандомного сервера, который обычно располагается еще и относительно близко к машине, скорость с которой измеряется. Это удобно, если надо оценить своего провайдера, или покрытие сотовой сети в определенном месте. Но у меня стояла другая задача - надо было измерить скорость между двумя конкретными узлами сети (на самом деле еще и построить мониторинг для этого!). Кажется, что можно было бы быстренько соорудить какой нибудь велосипед, перегоняя трафик из /dev/random в /dev/null через tcp-сокет, но зачем, если есть iperf3. Он умеет работать в клиент-серверном режиме, поддерживает авторизацию, поэтому можно не опасаться, что скрипт-киддисы будут заливать терабайты sql-инъекций и прочих Q-injection в наш сервак.

В этой небольшой заметке я расскажу как поднять iperf3 в режиме сервера, настроить аутентификацию клиентов и запускать iperf3-клиент на локальной машине для измерений точка-точка.

Генерим аутентификационные данные

Аутентификация iperf3 состояит из двух компонентов. Во первых, потребуется RSA-ключи для обеспечения шифрования передаваемых кредов пользователя, во вторых нужны эти самые креды. Ключи легко генерятся при помощи openssl (я рискну предположить, что если запускается всякий linux-софт, то есть доступ до консоли). Креды на сервере хранятся в хешированном виде, так что все довольно безопасно и утечки пароля опасаться не стоит, но тем не менее, пароль должен быть длинным, случайным, храниться в менеджере паролей. Имя пользователя - тоже, ну а че бы нет, не руками же его вводить.

Генерим RSA-ключи

Можно открыть man page, а можно скопирнуть команды ниже.

$ openssl genrsa -des3 -out private.pem 2048
$ openssl rsa -in private.pem -outform PEM -pubout -out public.pem
$ openssl rsa -in private.pem -out private_not_protected.pem -out-form PEM

Что теперь есть в каталоге где выполнялись команды: private.pem - приватный ключ, зашифрованный, public.pem - публичный ключ (он нужен клиентам для подключения), private_not_protected.pem - приватный ключ, незашифрованный (он понадобится серверу для работы в автоматическом режиме). Прихраним полученные артефакты в надежном месте до поры до времени.

Генерим креды пользователя

Вторым компонентом защиты от залива половины интернета в сервак iperf3 являются креды пользователя. Сервер употребляет их в хешированном и соленом виде, клиент требует ввод через stdin или можно передать в переменной окружения, если клиент работает в составе автоматизированного решения (запускается без участия человека).

Опять же, все описано в man, а можно скопирнуть отсюда:

$ S_USER=P3oUpiPcZ9hgeKRfsyVM S_PASSWD=q7m$H^R3dXuVT3(URy754bY9~q)T^Kut
$ echo -n "{$S_USER}$S_PASSWD" | sha256sum | awk '{ print $1 }'
9c37242bb7f83fef32689cb2005cc341dce3b424c48aa34c6a1cbc9d51c2b44b

Полученный хешик (9c37242bb7f83fef32689cb2005cc341dce3b424c48aa34c6a1cbc9d51c2b44b) вместе с именем пользователя надо прихранить в csv файле, который будет использоваться сервером.

P3oUpiPcZ9hgeKRfsyVM,9c37242bb7f83fef32689cb2005cc341dce3b424c48aa34c6a1cbc9d51c2b44b

Пользователей может быть несколько или даже много. Я очень надеюсь, что никто не догадается использовать логопасс из статьи, несмотря на то что они достаточно длинные и надежные :-)

Поднимаем сервер

А вот сейчас будет контент которого нет в man pages, так что… копируйте отсюда. Сервак будем крутить systemd юнитом. Для этого напишем вот такой незамысловатый файлик:

[Unit]
Description=Network speed test server
After=syslog.target network.target auditd.service

[Service]
ExecStart=/usr/bin/iperf3 -s --rsa-private-key-path /etc/iperf3/private_not_protected.pem --authorized-users-path /etc/iperf3/credentials.csv

[Install]
WantedBy=multi-user.target

И сложим его в /etc/systemd/system/iperf3.service. Внимательный читатель уже мог догадаться, куда надо сложить приватный ключ и файл с кредами. Ну конечно же в /etc/iperf3/! Можно сложить конечно куда то еще, в этом случае надо указать правильные пути к файлам через опции --rsa-private-key-path (для приватного ключа) и --authorized-users-path (для csv файлов с солеными и хешированными кредами). Chmod для этих файлов можно сделать побезопаснее:

-r--------  1 root root   71 Feb 11 10:24 credentials.csv
-r--------  1 root root 1.7K Feb 11 10:24 private_not_protected.pem

Приемлемо!

Запустить сервак проще простого:

# systemctl enable iperf3.service
# systemctl start iperf3.service

Готовенько! Можно запускать клиента.

Стартуем клиента

С клиентом все будет проще. Для запуска понадобится публичный ключ и логопасс, которые были созданы ранее. Для запуска “руками” пароль будет запрошен при старте приложения:

$ iperf3 --username P3oUpiPcZ9hgeKRfsyVM --rsa-public-key-path ./public.pem -c my.test.host.com
Password: Connecting to host my.test.host.com, port 5201
[  5] local 192.168.0.1 port 45540 connected to 42.69.666.777 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  10.4 MBytes  87.0 Mbits/sec    0   1.00 MBytes       
[  5]   1.00-2.00   sec  11.2 MBytes  94.4 Mbits/sec   33    834 KBytes       
[  5]   2.00-3.00   sec  11.2 MBytes  94.4 Mbits/sec  180    639 KBytes       
[  5]   3.00-4.00   sec  10.0 MBytes  83.9 Mbits/sec  105    488 KBytes       
[  5]   4.00-5.00   sec  7.50 MBytes  62.9 Mbits/sec    4    375 KBytes       
[  5]   5.00-6.00   sec  6.25 MBytes  52.4 Mbits/sec    0    403 KBytes       
[  5]   6.00-7.00   sec  8.75 MBytes  73.4 Mbits/sec    0    420 KBytes       
[  5]   7.00-8.00   sec  7.50 MBytes  62.9 Mbits/sec    0    427 KBytes       
[  5]   8.00-9.00   sec  8.75 MBytes  73.4 Mbits/sec    0    428 KBytes       
[  5]   9.00-10.00  sec  8.75 MBytes  73.4 Mbits/sec    0    434 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  90.4 MBytes  75.8 Mbits/sec  322             sender
[  5]   0.00-10.05  sec  88.2 MBytes  73.6 Mbits/sec                  receiver

iperf Done.

Пароль можно передать через переменную среды, это может понадобиться при запуске из другой софтины или скрипта:

$ export IPERF3_PASSWORD=q7m$H^R3dXuVT3(URy754bY9~q)T^Kut
$ iperf3 --username P3oUpiPcZ9hgeKRfsyVM --rsa-public-key-path ./public.pem -c my.test.host.com
Connecting to host my.test.host.com, port 5201
[  5] local 192.168.0.1 port 56308 connected to 42.69.666.777 port 5201
[ ID] Interval           Transfer     Bitrate         Retr  Cwnd
[  5]   0.00-1.00   sec  9.12 MBytes  76.5 Mbits/sec   67    526 KBytes       
[  5]   1.00-2.00   sec  10.0 MBytes  83.9 Mbits/sec    0    597 KBytes       
[  5]   2.00-3.00   sec  11.2 MBytes  94.4 Mbits/sec    0    648 KBytes       
[  5]   3.00-4.00   sec  8.75 MBytes  73.4 Mbits/sec  111    488 KBytes       
[  5]   4.00-5.00   sec  7.50 MBytes  62.9 Mbits/sec    1    477 KBytes       
[  5]   5.00-6.00   sec  7.50 MBytes  62.9 Mbits/sec    0    403 KBytes       
[  5]   6.00-7.00   sec  7.50 MBytes  62.9 Mbits/sec    0    428 KBytes       
[  5]   7.00-8.00   sec  7.50 MBytes  62.9 Mbits/sec    0    439 KBytes       
[  5]   8.00-9.00   sec  7.50 MBytes  62.9 Mbits/sec    1    328 KBytes       
[  5]   9.00-10.00  sec  6.25 MBytes  52.4 Mbits/sec    0    354 KBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate         Retr
[  5]   0.00-10.00  sec  82.9 MBytes  69.5 Mbits/sec  180             sender
[  5]   0.00-10.06  sec  80.2 MBytes  66.9 Mbits/sec                  receiver

iperf Done.

Это если из консоли, а если надо вызвать из дотнета, то переменную надо засунуть в коллекцию EnvironmentVariables объекта ProcessStartInfo:

var start = new ProcessStartInfo()
{
    FileName = "iperf3",
    Arguments = args.ToString(),
    RedirectStandardOutput = true
};
start.EnvironmentVariables.Add("IPERF3_PASSWORD", password);
var proc = new Process { StartInfo = start };
proc.Start();

Ну вот и все. Это оказалось проще чем казалось:-)