/* * Copyright (c) 2026 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using System.Security; using Microsoft.Win32; using ProtonVPN.IssueReporting.Contracts; using ProtonVPN.Logging.Contracts; using ProtonVPN.Logging.Contracts.Events.OperatingSystemLogs; namespace ProtonVPN.Vpn.Wintun; /** * Sometimes ComponentId is missing in the registry and OpenVPN won't find TUN adapter. * This class checks if the key is missing and creates one. */ public class WintunRegistryFixer : IWintunRegistryFixer { // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/system-defined-device-setup-classes-available-to-vendors private readonly string _regPath = "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e972-e325-11ce-bfc1-08002be10318}"; private readonly ILogger _logger; private readonly IIssueReporter _issueReporter; public WintunRegistryFixer(ILogger logger, IIssueReporter issueReporter) { _logger = logger; _issueReporter = issueReporter; } public void EnsureTunAdapterRegistryIsCorrect() { try { using RegistryKey? adaptersKey = Registry.LocalMachine.OpenSubKey(_regPath); if (adaptersKey == null) { return; } string[] folders = adaptersKey.GetSubKeyNames(); foreach (string folder in folders) { if (folder.Length != 4) { continue; } using (RegistryKey? adapterKey = Registry.LocalMachine.OpenSubKey($"{_regPath}\\{folder}")) { if (adapterKey == null) { continue; } string? matchingDeviceId = adapterKey.GetValue("MatchingDeviceId") as string; if (matchingDeviceId != "wintun") { continue; } string? componentId = adapterKey.GetValue("ComponentId") as string; if (string.IsNullOrEmpty(componentId)) { Registry.SetValue($"HKEY_LOCAL_MACHINE\\{_regPath}\\{folder}", "ComponentId", matchingDeviceId); _issueReporter.CaptureMessage("Fixed missing ComponentId on wintun adapter."); } else if (matchingDeviceId != componentId) { _logger.Info($"WintunRegistryFixer: ComponentId '{componentId}' " + $"has a value but is different from the MatchingDeviceId '{matchingDeviceId}'."); } } } } catch (SecurityException) { } } }