Простой VPN-туннель на C++17 для Linux.
Проект состоит из двух приложений:
vpn-server— серверная часть, поднимает TUN-интерфейс, настраивает NAT/forwarding и принимает UDP-пакеты от клиентов.vpn-client— клиентская часть, поднимает TUN-интерфейс, перенаправляет трафик через UDP-туннель на сервер.
Важно: проект предназначен для Linux и требует запуска от
root, так как использует/dev/net/tun, маршруты,iptablesи настройку сетевых интерфейсов.
- Создание TUN-интерфейса.
- UDP-туннель между клиентом и сервером.
- Шифрование трафика через
XChaCha20-Poly1305. - Проверка целостности и подлинности UDP-пакетов.
- Настройка маршрута по умолчанию на клиенте через VPN.
- Настройка NAT и forwarding на сервере.
- Настраиваемые параметры через командную строку.
- Логирование через
syslog. - Увеличение буферов UDP-сокета для повышения производительности.
Трафик шифруется на уровне UDP-пакетов:
TUN packet -> encrypt -> UDP -> decrypt -> TUN packet
По сети передаётся не открытый IP-пакет, а зашифрованный контейнер:
[magic: VPN1][nonce: 24 bytes][ciphertext + auth tag]
Используется алгоритм:
XChaCha20-Poly1305
Он обеспечивает:
- конфиденциальность — содержимое пакетов нельзя прочитать без ключа;
- целостность — изменение пакета приводит к ошибке расшифровки;
- базовую аутентификацию — пакет может создать только сторона, знающая общий ключ.
В текущей версии нет защиты от replay-атак. То есть злоумышленник теоретически может повторно отправить ранее перехваченный корректный пакет. Для production-использования нужно добавить счётчики пакетов и anti-replay window.
Нужны:
- C++17 compiler
- CMake
- Boost.Program_options
- fmt
- libsodium
- pthread
- iproute2
- iptables
- openssl — только для генерации ключа
apt update
apt install -y \
build-essential \
cmake \
libboost-program-options-dev \
libsodium-dev \
libfmt-dev \
iproute2 \
iptables \
opensslmkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .После сборки бинарники будут примерно здесь:
build/src/server/vpn-server
build/src/client/vpn-clientКлиент и сервер должны использовать одинаковый общий ключ.
Сгенерировать ключ можно так:
openssl rand -base64 32Пример результата:
CvEE3TRqqNNpmxy+/kk07Qk9912ZyCqUlv0ay5006KY=
Пример сохранения ключа в файл:
sudo mkdir -p /etc/myvpn
openssl rand -base64 32 | sudo tee /etc/myvpn/key
sudo chmod 600 /etc/myvpn/keyПосмотреть ключ:
sudo cat /etc/myvpn/keyСейчас ключ передаётся через параметр
--key. Это удобно для тестов, но не идеально с точки зрения безопасности, потому что аргументы процесса могут быть видны черезps. Более безопасный вариант — позже добавить параметр--key-file.
Минимальный пример:
sudo ./vpn-server \
--port 1194 \
--key 'CvEE3TRqqNNpmxy+/kk07Qk9912ZyCqUlv0ay5006KY='Полный пример:
sudo ./vpn-server \
--port 1194 \
--mtu 1380 \
--tun-name tun0 \
--tun-ip 192.168.200.1 \
--key 'CvEE3TRqqNNpmxy+/kk07Qk9912ZyCqUlv0ay5006KY='| Параметр | Коротко | Описание | По умолчанию |
|---|---|---|---|
--help |
-h |
Показать справку | — |
--port |
-p |
UDP-порт сервера | обязательный |
--mtu |
-m |
MTU TUN-интерфейса | 1420 |
--tun-name |
-n |
Имя TUN-интерфейса | tun0 |
--tun-ip |
-i |
IP-адрес TUN-интерфейса сервера | 192.168.200.1 |
--key |
-k |
Общий ключ шифрования | обязательный |
Минимальный пример:
sudo ./vpn-client \
--server <SERVER_PUBLIC_IP> \
--port 1194 \
--key 'CvEE3TRqqNNpmxy+/kk07Qk9912ZyCqUlv0ay5006KY='Пример:
sudo ./vpn-client \
--server 1.2.3.4 \
--port 1194 \
--mtu 1380 \
--tun-name tun0 \
--tun-ip 192.168.200.2 \
--key 'CvEE3TRqqNNpmxy+/kk07Qk9912ZyCqUlv0ay5006KY='| Параметр | Коротко | Описание | По умолчанию |
|---|---|---|---|
--help |
-h |
Показать справку | — |
--server |
-s |
Публичный IP сервера | обязательный |
--port |
-p |
UDP-порт сервера | обязательный |
--mtu |
-m |
MTU TUN-интерфейса | 1420 |
--tun-name |
-n |
Имя TUN-интерфейса | tun0 |
--tun-ip |
-i |
IP-адрес TUN-интерфейса клиента | 192.168.200.2 |
--key |
-k |
Общий ключ шифрования | обязательный |
После включения шифрования каждый UDP-пакет становится больше примерно на:
4 bytes magic + 24 bytes nonce + 16 bytes auth tag = 44 bytes
Поэтому рекомендуется использовать MTU 1380:
--mtu 1380Если оставить слишком большой MTU, возможна фрагментация UDP-пакетов и падение скорости.
На сервере:
ip addr show tun0
ip route
sudo iptables -t nat -L -n -v
sudo iptables -L FORWARD -n -vНа клиенте:
ip addr show tun0
ip route
ping 192.168.200.1Проверка внешнего IP через VPN:
curl ifconfig.meПроект пишет логи в syslog.
Просмотр логов через journalctl:
journalctl -f -t vpn-server
journalctl -f -t vpn-clientТрафик уже шифруется через XChaCha20-Poly1305, но проект всё ещё не является полноценным production-ready VPN.
Ограничения текущей версии:
- нет защиты от replay-атак;
- нет полноценного handshake;
- нет автоматической ротации ключей;
- общий ключ передаётся через аргумент командной строки;
- нет разделения ключей по направлениям
client -> serverиserver -> client.
Что стоит добавить позже:
--key-fileвместо--key;- счётчики пакетов;
- anti-replay window;
- разные ключи на разные направления;
- handshake для обмена сессионными ключами;
- ротацию ключей.
