Легковесный VPN сервер и клиент на Go с современной криптографией и защитой от DPI.
- ✅ Реальное VPN подключение через TUN интерфейс (видно ОС как сетевое подключение)
- 🔐 Современная криптография (как в WireGuard):
- Noise Protocol (
Noise_IK_25519_ChaChaPoly_BLAKE2s) для handshake - Curve25519 статические ключи-идентичности (аутентификация по публичным ключам)
- ChaCha20-Poly1305 для шифрования трафика
- Perfect Forward Secrecy за счёт эфемерных ключей в каждом handshake
- Периодический rehandshake (rekey) — ключи сессии ротируются без разрыва трафика (как в WireGuard)
- Noise Protocol (
- 🔑 Аутентификация по ключам: клиент пинит публичный ключ сервера, сервер сверяет ключ клиента со списком разрешённых (allowlist)
- 🛡️ Anti-replay (sequence number + sliding window, RFC 6479) и per-source-IP rate limiting против DoS
- 🚀 UDP транспорт - устойчивость к потерям пакетов
- 🎭 DPI Obfuscation - защита от глубокой проверки пакетов:
- Случайный префикс в каждом пакете
- Случайный padding для скрытия размера
- Шифрование делает содержимое неотличимым от случайных данных
- 🔄 Кросс-платформенность: Linux и Windows
┌─────────────┐ ┌─────────────┐
│ Client │ │ Server │
│ │ │ │
│ TUN iface │◄──────────────────────►│ TUN iface │
│ (10.0.0.2) │ Encrypted UDP │ (10.0.0.1) │
│ │ Noise + ChaCha20 │ │
└─────────────┘ + DPI Obfuscation └─────────────┘
Используется паттерн Noise_IK с набором примитивов WireGuard
(25519 / ChaChaPoly / BLAKE2s):
- У каждой стороны есть долговременная статическая пара ключей Curve25519
(«идентичность»). Приватный ключ хранится в файле (
-key-file), публичный — это «сертификат». - Клиент заранее знает и пинит публичный ключ сервера (
-server-key). Это аутентифицирует сервер и закрывает MITM — без приватного ключа сервер подменить нельзя. - Статический ключ клиента передаётся серверу внутри зашифрованного
handshake; сервер сверяет его с allowlist (
-peers) — так публичные ключи заменяют общий PSK. - Из handshake выводятся два симметричных ключа (по одному на направление) с Perfect Forward Secrecy (эфемерные ключи уникальны для каждой сессии).
Всего 2 сообщения (один round-trip), как в текущем дизайне.
Клиент (инициатор) раз в -rekey (по умолчанию 120 c) повторяет handshake →
обе стороны получают свежие эфемерные ключи. Прежняя сессия остаётся валидной
короткое grace-окно (~30 c) только для расшифровки пакетов «в полёте», так что
ротация ключей не рвёт трафик (в e2e-тесте — 0% потерь на 6+ ротациях).
- ChaCha20-Poly1305 (AEAD), отдельный ключ на каждое направление.
- Каждый data-кадр:
[counter(8)] [ciphertext] [tag(16)], где counter — это nonce шифра (монотонный, гарантирует уникальность nonce в сессии).
- На приёме — sequence number + скользящее окно 1024 (RFC 6479): каждый counter принимается ровно один раз; дубликаты и устаревшие кадры отбрасываются.
- Counter ставится в nonce только после успешной аутентификации, так что подделанный counter не сдвигает окно.
- Per-source-IP token-bucket на handshake (≈5/с, burst 10 на IP, до 4096 IP)
- глобальный backstop (≈100/с, burst 200). Дешёвая Noise-проверка отсеивает неаутентичные пакеты до дорогих операций.
[random_prefix(8)] [type(1)] [length(2)] [payload] [random_padding(0-64)]
payload для data-кадров — это [counter(8)] [ciphertext] [tag(16)], для
handshake — сырое сообщение Noise.
sudo apt update
sudo apt install -y build-essential golang-1.21- Go 1.21+
- Драйвер TAP-Windows (для TUN интерфейса)
make deps
make servermake clientmake windows-clientБинарник появится в bin/vpn-client.exe и его можно перенести на Windows.
make all-platforms# Ключ сервера: приватный → server.key, публичный → stdout
SERVER_PUB=$(./bin/keygen -out server.key)
# Ключ клиента: приватный → client.key, публичный → stdout
CLIENT_PUB=$(./bin/keygen -out client.key)
echo "server pub: $SERVER_PUB" # его пинит клиент (-server-key)
echo "client pub: $CLIENT_PUB" # его добавляет сервер в allowlist (-peers)Сервер и клиент также создают
*.keyавтоматически при первом запуске, если файла нет, и печатают свой публичный ключ в лог.*.keyв.gitignore.
# Требуется root для создания TUN интерфейса
sudo ./bin/vpn-server -listen 0.0.0.0:51820 -tun-ip 10.0.0.1/24 -peer-ip 10.0.0.2 \
-key-file server.key -peers "$CLIENT_PUB"Параметры:
-listen- адрес для прослушивания UDP (по умолчанию0.0.0.0:51820)-tun-ip- IP адрес TUN интерфейса на сервере (по умолчанию10.0.0.1/24)-peer-ip- IP адрес клиента (по умолчанию10.0.0.2)-mtu- MTU для TUN интерфейса (по умолчанию1420)-key-file- файл со статическим ключом сервера (создаётся, если нет)-peers- список разрешённых публичных ключей клиентов (base64, через запятую)-peers-file- то же из файла (по ключу на строку,#— комментарии). Если allowlist пуст — пускается любой криптографически валидный клиент (warning).
# Linux
sudo ./bin/vpn-client -server 172.26.171.205:51820 -tun-ip 10.0.0.2/24 -peer-ip 10.0.0.1 \
-key-file client.key -server-key "$SERVER_PUB"
# Windows (запустить от имени администратора)
# При первом запуске автоматически скачает wintun.dll и установит драйвер!
vpn-client.exe -server 172.26.171.205:51820 -tun-ip 10.0.0.2/24 -peer-ip 10.0.0.1 ^
-key-file client.key -server-key <SERVER_PUB>Windows особенности:
- ✅ Использует Wintun - современный драйвер от создателей WireGuard
- ✅ Автоматически скачивает wintun.dll при первом запуске
- ✅ Автоматически устанавливает драйвер (не нужны TAP-Windows или OpenVPN!)
- ✅ Требуется только права Администратора
См. подробную инструкцию: WINTUN_GUIDE.md
Параметры:
-server- адрес сервера (по умолчанию172.26.171.205:51820)-tun-ip- IP адрес клиента (по умолчанию10.0.0.2/24)-peer-ip- IP адрес сервера в VPN (по умолчанию10.0.0.1)-mtu- MTU (по умолчанию1420)-key-file- файл со статическим ключом клиента (создаётся, если нет)-server-key- обязательный публичный ключ сервера (base64) для пиннинга-rekey- интервал периодического rehandshake (по умолчанию120s;0— выкл.)
# Проверить TUN интерфейс
ip addr show vpn0
# Пинг клиента
ping 10.0.0.2# Linux
ip addr show vpn0
ping 10.0.0.1
# Windows
ipconfig
ping 10.0.0.1Сервер и клиент выводят подробные логи:
- Создание TUN интерфейса
- Статические публичные ключи (свой и пира)
- Установка аутентифицированной Noise-сессии
- Отклонённые/неавторизованные handshake
- Ошибки шифрования/дешифрования
- ✅ Noise_IK handshake (Curve25519 + ChaCha20-Poly1305 + BLAKE2s) — как в WireGuard
- ✅ Аутентификация по публичным ключам: пиннинг ключа сервера (анти-MITM) + allowlist ключей клиентов (вместо общего PSK)
- ✅ Perfect Forward Secrecy — эфемерные ключи в каждом handshake
- ✅ Периодический rehandshake — ротация ключей сессии без разрыва трафика
- ✅ Replay protection (sequence number + sliding window, RFC 6479)
- ✅ DoS protection — per-source-IP rate limiting + глобальный backstop
- ✅ DPI obfuscation — случайный префикс/padding
- Сертификаты/CA вместо ручного allowlist публичных ключей
- Более сложная обфускация (имитация HTTPS/DNS)
# Нужны root права
sudo ./bin/vpn-server- Установите TAP-Windows
- Или используйте Wintun
# Linux
sudo ufw allow 51820/udp
# Windows - добавьте правило в Windows Firewall для порта 51820 UDP.
├── cmd/
│ ├── server/ # VPN сервер
│ ├── client/ # VPN клиент
│ └── keygen/ # Генератор статических ключей-идентичностей
├── pkg/
│ ├── session/ # Noise_IK handshake, транспорт, анти-replay, идентичности + тесты
│ ├── transport/ # UDP транспорт с обфускацией + тесты/фаззинг
│ ├── ipparse/ # Разбор IPv4 для логов (общий для server/client) + тесты
│ ├── ratelimit/ # Token-bucket + per-IP лимитер (анти-DoS) + тесты
│ └── tun/ # TUN интерфейс (Linux/Windows)
├── scripts/
│ └── integration-test.sh # End-to-end тест через network namespaces
├── Makefile # Сборка и тесты
└── README.md # Документация
make test # go test ./...
make test-race # go test -race ./...Покрывают: полный Noise_IK handshake и транспорт, защиту от MITM (неверный
пиннинг ключа сервера), отклонение replay/подделки, out-of-order в окне,
ротацию ключей (rehandshake) с grace-окном, round-trip идентичностей,
sliding-window фильтр, per-IP rate limiting, сериализацию пакетов и фаззинг
Unmarshal, разбор IPv4/ICMP (в т.ч. с IP-опциями).
Поднимает сервер и клиент в двух изолированных network namespaces, соединённых
veth, и проверяет реальное прохождение ICMP через зашифрованный туннель в обе
стороны, отсутствие открытого payload на проводе (tcpdump), периодический
rehandshake (0% потерь на нескольких ротациях ключей), а также негативные
сценарии: неавторизованный клиент (нет в allowlist) и MITM (клиент пинит
неверный ключ сервера) — оба должны быть отклонены:
make integration-test # требует root (sudo)
# или напрямую:
sudo bash scripts/integration-test.sh- Throughput: ChaCha20-Poly1305 даёт стабильную скорость даже без AES-NI.
- Latency: +1-2ms overhead от шифрования.
- CPU: один Noise-handshake на подключение; data-path — потоковый AEAD.
MIT
Pull requests приветствуются! Особенно интересны улучшения:
- Более продвинутая обфускация
- Поддержка нескольких клиентов на сервере
- Web UI для управления
- Маршрутизация трафика