/*
* Copyright (c) 2023 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;
using System.Collections.Generic;
using ProtonVPN.Common.Core.Extensions;
using ProtonVPN.Common.Core.Networking;
namespace ProtonVPN.Vpn.Management
{
///
/// Parses an error message received from OpenVPN management interface.
///
public class ManagementError
{
private static readonly Dictionary> ErrorMap = new()
{
[VpnError.TapAdapterInUseError] = ContainsTapInUseError,
[VpnError.NoTapAdaptersError] = ContainsNoTapError,
[VpnError.TapRequiresUpdateError] = ContainsTapRequiresUpdateError,
[VpnError.AdapterTimeoutError] = ContainsTimeoutError,
[VpnError.NetshError] = ContainsNetshError,
[VpnError.TlsCertificateError] = ContainsTlsCertificateError,
[VpnError.ClientKeyMismatch] = ContainsKeyVerificationError,
};
public string Message { get; }
public ManagementError(string message)
{
Message = message;
}
public VpnError GetVpnError() => GetErrorType();
public static bool ContainsError(string message)
{
return message.StartsWithIgnoringCase(">FATAL") ||
message.StartsWithIgnoringCase(">PASSWORD:Verification Failed: 'Auth'") ||
ContainsTlsError(message) ||
ContainsTlsCertificateError(message);
}
private VpnError GetErrorType()
{
foreach (KeyValuePair> mapItem in ErrorMap)
{
if (mapItem.Value(Message))
{
return mapItem.Key;
}
}
return VpnError.Unknown;
}
private static bool ContainsNetshError(string message)
{
return message.ContainsIgnoringCase("NETSH: command failed");
}
private static bool ContainsTapInUseError(string message)
{
return message.ContainsIgnoringCase("All TAP-Windows adapters on this system are currently in use")
|| message.ContainsIgnoringCase("All TAP-Win32 adapters on this system are currently in use")
|| message.ContainsIgnoringCase("Failed to open wintun adapter");
}
private static bool ContainsNoTapError(string message)
{
return message.ContainsIgnoringCase("There are no TAP-Windows adapters on this system")
|| message.ContainsIgnoringCase("There are no TAP-Win32 adapters on this system");
}
private static bool ContainsTapRequiresUpdateError(string message)
{
return message.ContainsIgnoringCase(
"This version of OpenVPN requires a TAP-Windows driver that is at least version")
|| message.ContainsIgnoringCase(
"This version of OpenVPN requires a TAP-Win32 driver that is at least version");
}
private static bool ContainsTlsError(string message)
{
return message.StartsWithIgnoringCase(">STATE:") && message.ContainsIgnoringCase(",RECONNECTING,tls-error,");
}
private static bool ContainsTlsCertificateError(string message)
{
return message.StartsWithIgnoringCase(">LOG:") && (
message.ContainsIgnoringCase("VERIFY ERROR:") ||
message.ContainsIgnoringCase("VERIFY SCRIPT ERROR:"));
}
private static bool ContainsTimeoutError(string message)
{
return message.ContainsIgnoringCase("Timeout");
}
private static bool ContainsKeyVerificationError(string message)
{
return message.ContainsIgnoringCase("private key password verification failed");
}
}
}