Настройка OpenVPN с поддержкой Data Channel Offload (DCO) на Fedora 38

In the previous article we've looked how to deploy OpenVPN DCO on a Rocky Linux 9 system and about new technology in general. Here I'd like to describe how to do the same, but for Fedora 38.

Итак, имеем систему на Fedora 38, которая бежит на ядре 6.4.14-200.fc38.x86_64, установлен openvpn из стандартных репозиториев Fedora:

# dnf info openvpn
Last metadata expiration check: 1:12:41 ago on Sun 10 Sep 2023 03:31:03 PM MSK.
Installed Packages
Name         : openvpn
Version      : 2.6.6
Release      : 1.fc38
Architecture : x86_64
Size         : 1.7 M
Source       : openvpn-2.6.6-1.fc38.src.rpm
Repository   : @System
From repo    : updates
Summary      : A full-featured TLS VPN solution (beta release)
URL          : https://community.openvpn.net/
License      : GPLv2
Description  : OpenVPN is a robust and highly flexible tunneling application that uses all
             : of the encryption, authentication, and certification features of the
             : OpenSSL library to securely tunnel IP networks over a single UDP or TCP
             : port.  It can use the Marcus Franz Xaver Johannes Oberhumers LZO library
             : for compression.

Для того, чтобы включить поддержку DCO, необходимо установить модуль ядра ovpn-dco. Сделать это можно через copr репозиторий openvpn3, либо из исходников, взяв последние из репозитория на GitHub или GitLab.

Установка через copr

Подключаем репозиторий и ставим пакет kmod-ovpn-dco.

# dnf copr enable dsommers/openvpn3
Enabling a Copr repository. Please note that this repository is not part
of the main distribution, and quality may vary.
...
Do you really want to enable copr.fedorainfracloud.org/dsommers/openvpn3? [y/N]: y
Repository successfully enabled.

Ставим пакет:

# dnf install -y kmod-ovpn-dco

Во время установки на систему приедет пакет kmod-ovpn-dco с исходниками модуля ядра и запустится его сборка при помощи DKMS.

Однако, на момент написания этого поста установка заканчивалась неудачей.

Ошибка во время dnf install
Running transaction
  Preparing        :                                                                                                                                                                                                                      1/1
  Installing       : kernel-devel-matched-6.4.14-200.fc38.x86_64                                                                                                                                                                          1/3
  Installing       : dkms-3.0.11-1.fc38.noarch                                                                                                                                                                                            2/3
  Running scriptlet: dkms-3.0.11-1.fc38.noarch                                                                                                                                                                                            2/3
Created symlink /etc/systemd/system/multi-user.target.wants/dkms.service → /usr/lib/systemd/system/dkms.service.

  Installing       : kmod-ovpn-dco-0-20220905git3ba6c07.fc38.noarch                                                                                                                                                                       3/3
  Running scriptlet: kmod-ovpn-dco-0-20220905git3ba6c07.fc38.noarch                                                                                                                                                                       3/3
Loading new ovpn-dco-0.20220905git3ba6c07.fc38 DKMS files...
Deprecated feature: REMAKE_INITRD (/usr/src/ovpn-dco-0.20220905git3ba6c07.fc38/dkms.conf)
Building for 6.4.14-200.fc38.x86_64
Building initial module for 6.4.14-200.fc38.x86_64
Deprecated feature: REMAKE_INITRD (/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/source/dkms.conf)
Error! Bad return status for module build on kernel: 6.4.14-200.fc38.x86_64 (x86_64)
Consult /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/make.log for more information.
warning: %post(kmod-ovpn-dco-0-20220905git3ba6c07.fc38.noarch) scriptlet failed, exit status 10

Error in POSTIN scriptlet in rpm package kmod-ovpn-dco
  Verifying        : kmod-ovpn-dco-0-20220905git3ba6c07.fc38.noarch                                                                                                                                                                       1/3
  Verifying        : dkms-3.0.11-1.fc38.noarch                                                                                                                                                                                            2/3
  Verifying        : kernel-devel-matched-6.4.14-200.fc38.x86_64                                                                                                                                                                          3/3

Installed:
  dkms-3.0.11-1.fc38.noarch                                         kernel-devel-matched-6.4.14-200.fc38.x86_64                                         kmod-ovpn-dco-0-20220905git3ba6c07.fc38.noarch

Complete!

Из лога видно, что во время сборки модуля ядра произошла ошибка и указан файл, в котором можно посмотреть логи сборки модуля для получения подробностей.

Лог сборки
# cat /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/make.log
DKMS make.log for ovpn-dco-0.20220905git3ba6c07.fc38 for kernel 6.4.14-200.fc38.x86_64 (x86_64)
Sun Sep 10 03:31:13 PM MSK 2023
make: Entering directory '/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build'
/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/gen-compat-autoconf.sh /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/compat-autoconf.h
make -C /lib/modules/6.4.14-200.fc38.x86_64/build M=/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build PWD=/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build REVISION=copr:0.20220905git3ba6c07.fc38 CONFIG_OVPN_DCO=m INSTALL_MOD_DIR=updates/ modules
make[1]: Entering directory '/usr/src/kernels/6.4.14-200.fc38.x86_64'
CC [M] /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/main.o
CC [M] /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/bind.o
CC [M] /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/crypto.o
CC [M] /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/ovpn.o
/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/ovpn.c: In function ‘ovpn_net_xmit’:
/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/ovpn.c:468:28: error: implicit declaration of function ‘skb_gso_segment’; did you mean ‘skb_gso_reset’? [-Werror=implicit-function-declaration]
468 | segments = skb_gso_segment(skb, 0);
| ^~~~~~~~~~~~~~~
| skb_gso_reset
/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/ovpn.c:468:26: warning: assignment to ‘struct sk_buff *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
468 | segments = skb_gso_segment(skb, 0);
| ^
CC [M] /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/peer.o
cc1: some warnings being treated as errors
make[3]: *** [scripts/Makefile.build:252: /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/ovpn.o] Error 1
make[3]: *** Waiting for unfinished jobs....
/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/peer.c: In function ‘ovpn_peer_create’:
/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/peer.c:91:9: error: implicit declaration of function ‘netif_tx_napi_add’; did you mean ‘netif_napi_add’? [-Werror=implicit-function-declaration]
91 | netif_tx_napi_add(ovpn->dev, &peer->napi, ovpn_napi_poll,
| ^~~~~~~~~~~~~~~~~
| netif_napi_add
cc1: some warnings being treated as errors
make[3]: *** [scripts/Makefile.build:252: /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco/peer.o] Error 1
make[2]: *** [scripts/Makefile.build:497: /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build/drivers/net/ovpn-dco] Error 2
make[1]: *** [Makefile:2050: /var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build] Error 2
make[1]: Leaving directory '/usr/src/kernels/6.4.14-200.fc38.x86_64'
make: *** [Makefile:52: all] Error 2
make: Leaving directory '/var/lib/dkms/ovpn-dco/0.20220905git3ba6c07.fc38/build'

Ключевая ошибка здесь в следующем: implicit declaration of function ‘skb_gso_segment’; did you mean ‘skb_gso_reset’?

На эту тему как раз есть давно закрытый issue в github: https://github.com/OpenVPN/ovpn-dco/issues/42. Почему автор, после того как поправил ошибку, не обновил пакет в copr – загадка, которую попробую выяснить.

В общем, пока из copr не получится установить на современные ядра (если у вас более старое ядро, можно попробовать установить из copr), ставить как и в случае с Rocky Linux, из исходников.

Установка ovpn-dco из исходников

Для того, чтобы поставить все из исходников, нам понадобятся следующие пакеты:

  • gcc
  • git
  • kernel-devel
  • kernel-headers
  • make

Ставим их: dnf install -y git gcc kernel-headers kernel-devel make

Далее клонируем репозиторий с исходниками, заходим в него и запускаем сборку:

# git clone https://github.com/openvpn/ovpn-dco.git
# cd ovpn-dco
# make

В результате вы должны увидеть примерно следующий лог сборки make:

# make
/root/ovpn-dco/gen-compat-autoconf.sh /root/ovpn-dco/compat-autoconf.h
make -C /lib/modules/6.4.14-200.fc38.x86_64/build M=/root/ovpn-dco PWD=/root/ovpn-dco REVISION=0.2.20230426-1-gdba96d2 CONFIG_OVPN_DCO_V2=m INSTALL_MOD_DIR=updates/ modules
make[1]: Entering directory '/usr/src/kernels/6.4.14-200.fc38.x86_64'
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/main.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/bind.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/crypto.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/ovpn.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/peer.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/sock.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/stats.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/netlink.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/crypto_aead.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/pktid.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/tcp.o
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/udp.o
LD [M] /root/ovpn-dco/drivers/net/ovpn-dco/ovpn-dco-v2.o
MODPOST /root/ovpn-dco/Module.symvers
CC [M] /root/ovpn-dco/drivers/net/ovpn-dco/ovpn-dco-v2.mod.o
LD [M] /root/ovpn-dco/drivers/net/ovpn-dco/ovpn-dco-v2.ko
BTF [M] /root/ovpn-dco/drivers/net/ovpn-dco/ovpn-dco-v2.ko
Skipping BTF generation for /root/ovpn-dco/drivers/net/ovpn-dco/ovpn-dco-v2.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/kernels/6.4.14-200.fc38.x86_64'

В логе не видно никаких ошибок, значит можно попробовать установить модуль ядра в систему:

# make install
/root/ovpn-dco/gen-compat-autoconf.sh /root/ovpn-dco/compat-autoconf.h
make -C /lib/modules/6.4.14-200.fc38.x86_64/build M=/root/ovpn-dco PWD=/root/ovpn-dco REVISION=0.2.20230426-1-gdba96d2 CONFIG_OVPN_DCO_V2=m INSTALL_MOD_DIR=updates/ modules_install
make[1]: Entering directory '/usr/src/kernels/6.4.14-200.fc38.x86_64'
INSTALL /lib/modules/6.4.14-200.fc38.x86_64/updates//drivers/net/ovpn-dco/ovpn-dco-v2.ko
SIGN /lib/modules/6.4.14-200.fc38.x86_64/updates//drivers/net/ovpn-dco/ovpn-dco-v2.ko
At main.c:167:
- SSL error:FFFFFFFF80000002:system library::No such file or directory: crypto/bio/bss_file.c:67
- SSL error:10000080:BIO routines::no such file: crypto/bio/bss_file.c:75
sign-file: ./certs/signing_key.pem
DEPMOD /lib/modules/6.4.14-200.fc38.x86_64
make[1]: Leaving directory '/usr/src/kernels/6.4.14-200.fc38.x86_64'
depmod -a

Не смотря на ошибки SSL, модуль установился нормально и виден в системе. Даже нормально загружается и выгружается:

# modinfo ovpn-dco-v2
filename: /lib/modules/6.4.14-200.fc38.x86_64/updates/drivers/net/ovpn-dco/ovpn-dco-v2.ko
alias: net-pf-16-proto-16-family-ovpn-dco-v2
alias: rtnl-link-ovpn-dco
version: 0.2.20230426-1-gdba96d2
license: GPL
author: (C) 2020-2023 OpenVPN, Inc.
description: OpenVPN data channel offload (ovpn-dco)
rhelversion: 9.99
srcversion: 045BF0F4AB0BEC5963517E6
depends: udp_tunnel,ip6_udp_tunnel
retpoline: Y
name: ovpn_dco_v2
vermagic: 6.4.14-200.fc38.x86_64 SMP preempt mod_unload
# modprobe ovpn-dco-v2
# rmmod ovpn-dco-v2

В dmesg видим следующие сообщения, о том, что модуль был установлен отдельно от ядра, успешно загрузился, однако не прошёл проверку подписи. Автор утверждает, что в этом нет ничего страшного.

[ 2332.779985] ovpn_dco_v2: loading out-of-tree module taints kernel.
[ 2332.780013] ovpn_dco_v2: module verification failed: signature and/or required key missing - tainting kernel
[ 2332.781283] OpenVPN data channel offload (ovpn-dco) 0.2.20230426-1-gdba96d2 -- (C) 2020-2023 OpenVPN, Inc.

Включаем DCO

Итак, модуль ядра ovpn-dco мы собрали и установили, теперь самое время проверить конфигурационные параметры OpenVPN, чтобы они не мешали включению DCO. А именно (повторим из прошлой статьи):

Требования

Версия openvpn. Поддержка DCO в openvpn появилась в версии 2.6. Значит openvpn должен быть этой или более высокой версии. Также можно проверить, что поддержка DCO была включена при сборке:

# openvpn --version | grep DCO
OpenVPN 2.6.6 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
DCO version: N/A

[DCO] в первой строчке указывает, что openvpn бинарный файл был собран со включенной поддержкой DCO – то, что нам надо.

Наличие модуля ядра ovpn-dco. Наличие присутствует. Мы только что его собрали и установили.

Совместимые режимы шифрования. DCO поддерживается только при использовании AEAD режиме шифра. А именно, поддерживаются AES-***-GCM и ChaCha20-Poly1305.

Драйвер. Для разгрузки поддерживается только tun (L3) драйвер. Если у вас режим работы tap (L2), то можете закрывать эту заметку, либо подумать о переходе на L3 VPN (tun).

В любом случае, если какие-то из настроек не подходят для активации режима DCO, openvpn вам об этом скажет в логах. Поэтому обязательно читайте их!

Перезапускаем openvpn и смотрим логи:

# systemctl restart openvpn-server@<config_name>
# journalctl -u openvpn-server@<config_name>

В логах сразу после старта сервиса вы можете увидеть, например, такие сообщения:

  • Note: cipher 'AES-256-CBC' in --data-ciphers is not supported by ovpn-dco, disabling data channel offload. – такая ошибка появляется, когда в конфиге не указаны data-ciphers и туда по умолчанию попадают все поддерживаемые системой шифры. В т.ч. неподдерживаемые режимом DCO.
  • Note: Kernel support for ovpn-dco missing, disabling data channel offload. – это можно увидеть в случае, если модуль ядра не установлен в системе.

Нужно устранить причины появления ошибок. Обратите внимание, что если вы будете на рабочей системе менять набор шифров, то убедитесь, что все ваши клиенты поддерживают новые шифры, а также что в конфигах клиентов не указан какой-то конкретный, например, AES-***-CBC, который перестанет работать после явного перечисления AES-***-GCM шифров на сервере. Иначе клиент просто не сможет подключиться из-за несовпадающих шифров.

После устранения всех несовместимых с DCO параметров настроек, в логах вы увидите следующее:

DCO version: 0.2.20230426-1-gdba96d2
...
DCO device tun0 opened

Также, можно проверить, что tun# устройство работает под собранным нами драйвером ovpn-dco:

# ethtool -i tun0
driver: ovpn-dco
version: 0.2.20230426-1-gdba96d2
firmware-version:
expansion-rom-version:
bus-info: ovpn
supports-statistics: no
supports-test: no
supports-eeprom-access: no
supports-register-dump: no
supports-priv-flags: no

Останется лишь проверить наличие связи, подняв соединение с VPN-сервером. Также можно проверить, что при передаче трафика не используется openvpn процесс. Как это сделать – смотрите в конце предыдущей статьи.

Приятного пользования!

Leave a Reply

Your email address will not be published. Required fields are marked *

Optimized by Optimole
en_USEnglish