[0.8.1] - 2026-06-16
Added
- Subnet split-tunnel on all GUI clients — users can now specify per-CIDR route exclusions that bypass the VPN tunnel; exclusions are persisted and forwarded to the underlying
aivpn-clientsubprocess as--exclude-routeargs (iOS:SplitTunnelView+NEIPv4Settings.excludedRoutes; macOS:ContentViewCIDR field +VPNManagersubprocess passthrough; Windows: egui multiline input +vpn_manager.rssubprocess passthrough; Android: DNS-resolved per-domain exclusions viaBuilder.excludeRoute(IpPrefix)on API 33+, graceful skip + warning on older devices) - Domain-based split-tunnel on Android —
AivpnService.applyDomainExclusions()resolves saved excluded domains at connect time viaInetAddress.getAllByName()and adds per-IP exclusion routes; includes API level check with user-visible warning on API < 33 --exclude-routeflag inaivpn-client— newAppendCLI argument for repeatable CIDR subnet exclusions passed through from all GUI clients- Kill-switch toggle in Windows GUI — checkbox wired to
--kill-switchsubprocess argument invpn_manager.rs - UAC elevation manifest — Windows build now embeds
requireAdministratorexecution level in the application manifest viabuild.rs, eliminating silent access-denied failures on first run - Adaptive mode forwarded to iOS tunnel extension —
adaptiveModeflag is now included inproviderConfigurationbyVPNManager.connect()and read insidePacketTunnelProvider - Recording IPC response in iOS tunnel extension —
handleAppMessagenow returns{"canRecord": false}forrecord_start/record_stop/record_statusrequests, preventing the UI from stalling in.startingstate - Audit log wired into gateway —
AuditLoggeris now passed intoGatewayServerand records events for: ClientCert accepted/rejected, RecordingStart, RecordingStop, PoolSync rejected
Security
- ServerHello signature verification (
C-CL-1, CRITICAL) —aivpn-clientnow verifies the ed25519 signature inServerHelloagainstserver_signing_keybefore completing the PFS ratchet; a bad signature disconnects immediately, preventing MitM key substitution - MaskUpdate signature verification (
C-CL-2, CRITICAL) — mask profiles received viaControlPayload::MaskUpdateare now verified against the server's signing key before being applied; unsigned or tampered masks are silently ignored - BootstrapDescriptorUpdate signature enforcement (
C-CL-3, CRITICAL) —store_verified_descriptor()is now called with the server's static key astrusted_keyinstead ofNone; descriptors without a valid signature are rejected - Bootstrap SSRF guard (
C-CL-4) —bootstrap_loader.rsvalidates all URLs fetched from thebufield before making HTTP requests; non-HTTPS schemes and private/loopback hosts (127.x, 10.x, 192.168.x, 172.16–31.x, 169.254.x, ::1) are rejected with an error log - iOS connection keys moved to Keychain (
C-I-1, CRITICAL) —KeychainStoragenow usesSecurity.framework(SecItemAdd/SecItemCopyMatching/SecItemUpdate/SecItemDelete) withkSecAttrAccessibleWhenUnlockedThisDeviceOnly; no connection keys or mTLS certs are written toUserDefaults - macOS helper
binaryPathrestricted to allowlist (C-M-1, CRITICAL) —aivpn-helpernow rejects anybinaryPathnot in a hardcoded set of canonical paths before callingposix_spawn; eliminates local privilege escalation via socket message injection - macOS PSK plaintext write removed (
C-M-2, CRITICAL) —VPNManager.saveKey()no longer writes the connection key toUserDefaults; key storage is Keychain-only - ChainForward source IP validated (
C-S-4) —gateway.rsnow parses the IPv4 source address from the inner payload and confirms it matches the forwarding session's assigned VPN IP before writing to the TUN channel; IPv6 inner payloads are blocked unconditionally; mismatches are logged and dropped - Pre-ratchet anti-replay bitmap (
C-S-2) —Sessiongains apre_ratchet_bitmapfield that marks consumed pre-ratchet tag counters, preventing replay of packets captured before a key rotation; bitmap is cleared oncomplete_ratchet() - PoolSync guard against non-pool sessions (
C-S-1) —is_pool_peerflag validated before accepting anyPoolSyncmessage, preventing arbitrary clients from injecting client-DB records
Fixed
tun_nameshell injection (H-S-3) —nat.rsvalidates the TUN interface name against^[a-z][a-z0-9_-]{0,14}$before it is used in any nftables / iptables command; invalid names are rejected with an error before any firewall rule is applied- PoolSync VPN IP collision (
H-S-2) —client_db.merge_from_json()now checks for duplicate VPN IPs before inserting a synced client record; conflicts are logged and the incoming record is skipped passive_distributionpanics removed (H-S-6) —encode_for_image()andencode_for_blockchain()no longer callunimplemented!(); they emit awarn!and returnErr, allowing the server to continue running- ClientCert sent after PFS ratchet (
H-CL-1) —aivpn-clientnow queuesClientCertinside theServerHellohandler aftercomplete_ratchet(), ensuring the cert is encrypted with ratcheted session keys - MessagePack size limit for bootstrap descriptors (
H-CL-6) —BootstrapDescriptorUpdatehandler rejects payloads larger than 512 KiB beforermp_serde::from_slice, preventing OOM from oversized control messages - iOS 104-byte mTLS cert check removed —
PacketTunnelProviderno longer rejects certs that are not exactly 104 bytes; any non-empty base64-decoded value is accepted - iOS
LocalizationManagercrash on iOS 15 —Locale.current.language.languageCodegated behind#available(iOS 16, *); falls back toLocale.current.languageCode - Android
onRevoke()infinite reconnect —AivpnService.onRevoke()now setsmanualDisconnect = truebeforesuper.onRevoke(), preventing the reconnect loop triggered by OS-initiated VPN revocation - Android
@Volatilecallback race —statusCallback,trafficCallback, andtileCallbackinvocations now capture the reference in a localvalbefore the null-check and invoke - Android callbacks leaked in
onDestroy—AivpnService.onDestroy()now nullifies all three callbacks beforesuper.onDestroy() - Android bench
DatagramSocketnot protected — the UDP RTT probe socket inMainActivitynow callsVpnService.protect()before sending, preventing a routing loop when VPN is active - iOS
syncStatus()called off main thread —VPNManagerwrapssyncStatus()inDispatchQueue.main.asyncinside theloadAllFromPreferencescompletion handler current_timestamp_ms()panic —.unwrap()replaced with.unwrap_or_default()inaivpn-common/src/crypto.rshandshake_locksunbounded growth — periodic gateway cleanup now prunes entries withArc::strong_count == 1- MikroTik container non-functional as gateway —
entrypoint.shrewritten: enablesnet.ipv4.ip_forward, installs idempotent MASQUERADE + FORWARD rules, quotesAIVPN_KEY, defaultsAIVPN_FULL_TUNNEL=false, adds 5-second restart loop;README.md/README_RU.md/README_CN.mdupdated withcap=net-adminin all/container/addexamples - Windows GUI abrupt exit —
main.rsno longer callsstd::process::exit(0); the tray thread is signalled and joined before the process exits naturally - macOS helper
mtlsCertPathpath traversal — helper now applies an allowlist prefix and extension check before accepting a cert path argument
Changed
- Version bumped 0.8.0 → 0.8.1 across workspace
Cargo.toml, all crateCargo.tomlfiles, macOSInfo.plist(CFBundleVersion 5 → 6), iOSApp/Info.plistandTunnel/Info.plist(CFBundleVersion 3 → 4), macOS/iOS version strings, Androidversion_footer - macOS helper now warns when mTLS cert path is configured but proxy mode is active
- Android
SplitTunnelActivityshows API-level note explaining domain exclusions require Android 10+
[0.8.1] — 2026-06-16
Добавлено
- Раздельное туннелирование по подсетям во всех GUI-клиентах — пользователи могут указывать исключения маршрутов по CIDR, которые обходят VPN-туннель; исключения сохраняются и передаются в subprocess
aivpn-clientчерез аргументы--exclude-route(iOS:SplitTunnelView+NEIPv4Settings.excludedRoutes; macOS: поле CIDR вContentView+ передача черезVPNManager; Windows: multiline-ввод в egui +vpn_manager.rs; Android: DNS-разрешённые исключения черезBuilder.excludeRoute(IpPrefix)на API 33+, graceful fallback с предупреждением на старых версиях) - Доменное split-tunnel на Android —
AivpnService.applyDomainExclusions()разрешает сохранённые исключённые домены черезInetAddress.getAllByName()при подключении и добавляет маршруты-исключения для каждого IP; включает проверку версии API с видимым предупреждением при API < 33 - Флаг
--exclude-routeвaivpn-client— новый аргумент типаAppendдля многократного указания CIDR-подсетей, передаваемых из GUI-клиентов - Kill-switch в Windows GUI — чекбокс подключён к аргументу
--kill-switchвvpn_manager.rs - Манифест UAC-повышения привилегий — сборка Windows теперь встраивает уровень выполнения
requireAdministratorв манифест приложения черезbuild.rs - Адаптивный режим передаётся в iOS tunnel extension — флаг
adaptiveModeтеперь включается вproviderConfigurationвVPNManager.connect()и читается вPacketTunnelProvider - Recording IPC ответ в iOS tunnel extension —
handleAppMessageвозвращает{"canRecord": false}на запросыrecord_start/record_stop/record_status, предотвращая зависание UI - Аудит-лог подключён к шлюзу —
AuditLoggerпередаётся вGatewayServerи фиксирует события: принятие/отклонение ClientCert, RecordingStart, RecordingStop, отклонённый PoolSync
Безопасность
- Верификация подписи ServerHello (
C-CL-1, КРИТИЧНО) —aivpn-clientпроверяет ed25519-подпись вServerHelloпоserver_signing_keyперед завершением PFS-рэтчета; неверная подпись разрывает соединение - Верификация подписи MaskUpdate (
C-CL-2, КРИТИЧНО) — профили масок изControlPayload::MaskUpdateпроверяются по ключу подписи сервера; неподписанные маски игнорируются - Верификация подписи BootstrapDescriptorUpdate (
C-CL-3, КРИТИЧНО) —store_verified_descriptor()вызывается со статическим ключом сервера какtrusted_key; дескрипторы без корректной подписи отклоняются - SSRF-защита в bootstrap_loader (
C-CL-4) — проверка всех URL из поляbu: только HTTPS, блокировка приватных и loopback-адресов - Ключи подключения iOS перемещены в Keychain (
C-I-1, КРИТИЧНО) —KeychainStorageиспользуетSecurity.frameworkсkSecAttrAccessibleWhenUnlockedThisDeviceOnly; ничего не пишется вUserDefaults - Ограничение
binaryPathв macOS helper (C-M-1, КРИТИЧНО) —aivpn-helperпринимает только пути из жёстко заданного allowlist передposix_spawn; устраняет локальное повышение привилегий - Удалена запись PSK в открытом виде в macOS (
C-M-2, КРИТИЧНО) —VPNManager.saveKey()больше не пишет ключ вUserDefaults - Валидация src IP в ChainForward (
C-S-4) —gateway.rsпроверяет IPv4-адрес источника внутренней нагрузки против VPN IP сессии; несоответствия и IPv6 отбрасываются - Bitmap анти-replay для pre-ratchet тегов (
C-S-2) — полеpre_ratchet_bitmapвSessionотмечает использованные счётчики тегов; сбрасывается приcomplete_ratchet() - Защита PoolSync от не-pool сессий (
C-S-1) — флагis_pool_peerпроверяется перед принятием любогоPoolSync
Исправлено
- Инъекция через
tun_name(H-S-3) — валидация по шаблону^[a-z][a-z0-9_-]{0,14}$вnat.rs - Коллизия VPN IP при PoolSync (
H-S-2) —merge_from_json()проверяет дублирование IP; конфликты пропускаются с предупреждением - Паники в
passive_distribution(H-S-6) —unimplemented!()заменены наErr+warn! - ClientCert отправляется после PFS рэтчета (
H-CL-1) — сертификат ставится в очередь внутри обработчикаServerHelloпослеcomplete_ratchet() - Лимит размера MessagePack (
H-CL-6) —BootstrapDescriptorUpdateотклоняет нагрузки > 512 КиБ - Проверка 104 байт mTLS в iOS убрана — принимается любое непустое base64-значение
- Краш
LocalizationManagerна iOS 15 —#available(iOS 16, *)guard дляLocale.current.language.languageCode - Бесконечный reconnect при
onRevoke()на Android —manualDisconnect = true+super.onRevoke() - Гонка
@Volatilecallback на Android — захват ссылки в локальныйvalперед null-проверкой - Утечка callbacks в
onDestroyна Android — обнуление всех callback передsuper.onDestroy() - Незащищённый
DatagramSocketбенчмарка на Android — вызовVpnService.protect()перед отправкой syncStatus()вне главного потока на iOS — оборачивается вDispatchQueue.main.async- Паника
current_timestamp_ms()—.unwrap()→.unwrap_or_default()вcrypto.rs - Неограниченный рост
handshake_locks— периодическая очистка поArc::strong_count == 1 - Нефункциональный контейнер MikroTik —
entrypoint.shпереписан;cap=net-adminдобавлен в README (EN/RU/CN) - Резкое завершение Windows GUI — graceful shutdown с join tray thread вместо
process::exit(0) - Path traversal
mtlsCertPathв macOS helper — allowlist-проверка префикса и расширения
Изменено
- Версия поднята с 0.8.0 до 0.8.1 во всём workspace:
Cargo.toml, crate-файлы, macOSInfo.plist(CFBundleVersion 5 → 6), iOSInfo.plist(CFBundleVersion 3 → 4), строки версий, Androidversion_footer - macOS helper предупреждает при активном proxy-режиме и настроенном mTLS-сертификате
SplitTunnelActivityна Android отображает примечание об уровне API для доменных исключений