Skip to content

Commit d823fa7

Browse files
Mindaugas VeblauskasThomas Felices
authored andcommitted
Add OpenVPN TCP for guest holes [VPNWIN-2832]
1 parent 4575640 commit d823fa7

File tree

13 files changed

+100
-21
lines changed

13 files changed

+100
-21
lines changed

src/Client/Logic/Connection/ProtonVPN.Client.Logic.Connection/RequestCreators/GuestHoleConnectionRequestCreator.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 Proton AG
2+
* Copyright (c) 2025 Proton AG
33
*
44
* This file is part of ProtonVPN.
55
*
@@ -23,6 +23,7 @@
2323
using ProtonVPN.Client.Logic.Connection.Contracts.RequestCreators;
2424
using ProtonVPN.Client.Settings.Contracts;
2525
using ProtonVPN.Common.Legacy.Vpn;
26+
using ProtonVPN.Configurations.Contracts;
2627
using ProtonVPN.EntityMapping.Contracts;
2728
using ProtonVPN.Logging.Contracts;
2829
using ProtonVPN.ProcessCommunication.Contracts.Entities.Settings;
@@ -32,30 +33,34 @@ namespace ProtonVPN.Client.Logic.Connection.RequestCreators;
3233

3334
public class GuestHoleConnectionRequestCreator : ConnectionRequestCreatorBase, IGuestHoleConnectionRequestCreator
3435
{
36+
private readonly IConfiguration _config;
3537
private readonly IConnectionKeyManager _connectionKeyManager;
3638

3739
public GuestHoleConnectionRequestCreator(
40+
IConfiguration config,
3841
ILogger logger,
3942
ISettings settings,
4043
IEntityMapper entityMapper,
4144
IConnectionKeyManager connectionKeyManager,
4245
IMainSettingsRequestCreator mainSettingsRequestCreator)
4346
: base(logger, settings, entityMapper, mainSettingsRequestCreator)
4447
{
48+
_config = config;
4549
_connectionKeyManager = connectionKeyManager;
4650
}
4751

4852
public async Task<ConnectionRequestIpcEntity> CreateAsync(IEnumerable<GuestHoleServerContract> servers)
4953
{
5054
MainSettingsIpcEntity settings = GetSettings();
51-
settings.VpnProtocol = VpnProtocolIpcEntity.WireGuardTls;
55+
settings.OpenVpnAdapter = OpenVpnAdapterIpcEntity.Tap;
56+
settings.VpnProtocol = VpnProtocolIpcEntity.Smart;
5257

5358
ConnectionRequestIpcEntity request = new()
5459
{
5560
RetryId = Guid.NewGuid(),
5661
Config = GetVpnConfig(settings),
5762
Credentials = await GetVpnCredentialsAsync(),
58-
Protocol = VpnProtocolIpcEntity.WireGuardTls,
63+
Protocol = VpnProtocolIpcEntity.Smart,
5964
Servers = GetVpnServers(servers),
6065
Settings = settings,
6166
};
@@ -68,19 +73,33 @@ protected override VpnConfigIpcEntity GetVpnConfig(MainSettingsIpcEntity setting
6873
return new()
6974
{
7075
VpnProtocol = settings.VpnProtocol,
71-
PreferredProtocols = [ VpnProtocolIpcEntity.WireGuardTls ],
72-
Ports = { { VpnProtocolIpcEntity.WireGuardTls, Settings.WireGuardTlsPorts } },
76+
PreferredProtocols = [
77+
VpnProtocolIpcEntity.WireGuardTls,
78+
VpnProtocolIpcEntity.OpenVpnTcp,
79+
],
80+
Ports = {
81+
{ VpnProtocolIpcEntity.WireGuardTls, Settings.WireGuardTlsPorts },
82+
{ VpnProtocolIpcEntity.OpenVpnTcp, Settings.OpenVpnTcpPorts },
83+
},
7384
};
7485
}
7586

7687
protected override Task<VpnCredentialsIpcEntity> GetVpnCredentialsAsync()
7788
{
7889
VpnCredentialsIpcEntity credentials = EntityMapper.Map<VpnCredentials, VpnCredentialsIpcEntity>(
79-
new VpnCredentials(_connectionKeyManager.GenerateTemporaryKeyPair()));
90+
new VpnCredentials(
91+
_connectionKeyManager.GenerateTemporaryKeyPair(),
92+
AddSuffixToUsername(_config.GuestHoleVpnUsername),
93+
_config.GuestHoleVpnPassword));
8094

8195
return Task.FromResult(credentials);
8296
}
8397

98+
private string AddSuffixToUsername(string username)
99+
{
100+
return username + _config.VpnUsernameSuffix;
101+
}
102+
84103
private VpnServerIpcEntity[] GetVpnServers(IEnumerable<GuestHoleServerContract> servers)
85104
{
86105
return servers

src/Configurations/ProtonVPN.Configurations.Contracts/IConfiguration.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 Proton AG
2+
* Copyright (c) 2025 Proton AG
33
*
44
* This file is part of ProtonVPN.
55
*
@@ -29,6 +29,8 @@ public interface IConfiguration : IStaticConfiguration
2929
string ApiVersion { get; }
3030
string ServerValidationPublicKey { get; }
3131

32+
string GuestHoleVpnUsername { get; }
33+
string GuestHoleVpnPassword { get; }
3234
string VpnUsernameSuffix { get; }
3335
string DoHVerifyApiHost { get; }
3436

src/Configurations/ProtonVPN.Configurations/Configuration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public partial class Configuration : StaticConfiguration, IConfiguration
3030
public string ApiVersion => Get();
3131
public string ServerValidationPublicKey => Get();
3232

33+
public string GuestHoleVpnUsername => Get();
34+
public string GuestHoleVpnPassword => Get();
3335
public string VpnUsernameSuffix => Get();
3436
public string DoHVerifyApiHost => Get();
3537

src/Configurations/ProtonVPN.Configurations/Defaults/DefaultConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ public static class DefaultConfiguration
144144

145145
public static string ServerValidationPublicKey => "MCowBQYDK2VwAyEANpYpt/FlSRwEuGLMoNAGOjy1BTyEJPJvKe00oln7LZk=";
146146
public static string VpnUsernameSuffix => "+pw"; // p - proton, w - windows
147+
public static string GuestHoleVpnUsername => "guest";
148+
public static string GuestHoleVpnPassword => "guest";
147149
public static string DoHVerifyApiHost => "verify-api.protonvpn.com";
148150

149151
public static string NtpServerUrl => "time.windows.com";

src/ProcessCommunication/ProtonVPN.ProcessCommunication.Contracts/Entities/Vpn/VpnCredentialsIpcEntity.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,10 @@ public class VpnCredentialsIpcEntity
3131

3232
[DataMember(Order = 2)]
3333
public AsymmetricKeyPairIpcEntity ClientKeyPair { get; set; }
34+
35+
[DataMember(Order = 3)]
36+
public string Username { get; set; }
37+
38+
[DataMember(Order = 4)]
39+
public string Password { get; set; }
3440
}

src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/ConnectionRequestMapperTest.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ public void TestMapLeftToRight()
117117
new VpnConfig(new VpnConfigParameters()),
118118
new VpnCredentials(string.Empty, DateTime.UtcNow.AddDays(1), new AsymmetricKeyPair(
119119
new SecretKey("PVPN", KeyAlgorithm.Unknown),
120-
new PublicKey("PVPN", KeyAlgorithm.Unknown))));
120+
new PublicKey("PVPN", KeyAlgorithm.Unknown)),
121+
"username",
122+
"password"));
121123

122124

123125
ConnectionRequestIpcEntity result = _mapper.Map(entityToTest);

src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping.Tests/Vpn/VpnCredentialsMapperTest.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,18 @@ public void TestMapLeftToRight_WithCertificate()
7171
DateTime.UtcNow.AddDays(1),
7272
new AsymmetricKeyPair(
7373
new SecretKey("PVPN", KeyAlgorithm.Ed25519),
74-
new PublicKey("PVPN", KeyAlgorithm.Ed25519)));
74+
new PublicKey("PVPN", KeyAlgorithm.Ed25519)),
75+
"username",
76+
"password");
7577

7678
VpnCredentialsIpcEntity result = _mapper.Map(entityToTest);
7779

7880
Assert.IsNotNull(result);
7981
Assert.AreEqual(entityToTest.ClientCertPem, result.Certificate.Pem);
8082
Assert.AreEqual(entityToTest.ClientCertificateExpirationDateUtc, result.Certificate.ExpirationDateUtc);
8183
Assert.AreEqual(_expectedAsymmetricKeyPairIpcEntity, result.ClientKeyPair);
84+
Assert.AreEqual(entityToTest.Username, result.Username);
85+
Assert.AreEqual(entityToTest.Password, result.Password);
8286
}
8387

8488
[TestMethod]
@@ -87,7 +91,9 @@ public void TestMapRightToLeft_WithCertificate()
8791
VpnCredentialsIpcEntity entityToTest = new()
8892
{
8993
Certificate = CreateCertificate(),
90-
ClientKeyPair = new AsymmetricKeyPairIpcEntity()
94+
ClientKeyPair = new AsymmetricKeyPairIpcEntity(),
95+
Username = "username",
96+
Password = "password",
9197
};
9298

9399
VpnCredentials result = _mapper.Map(entityToTest);
@@ -96,6 +102,8 @@ public void TestMapRightToLeft_WithCertificate()
96102
Assert.AreEqual(entityToTest.Certificate.Pem, result.ClientCertPem);
97103
Assert.AreEqual(entityToTest.Certificate.ExpirationDateUtc, result.ClientCertificateExpirationDateUtc);
98104
Assert.AreEqual(_expectedAsymmetricKeyPair, result.ClientKeyPair);
105+
Assert.AreEqual(entityToTest.Username, result.Username);
106+
Assert.AreEqual(entityToTest.Password, result.Password);
99107
}
100108

101109
private ConnectionCertificateIpcEntity CreateCertificate()

src/ProcessCommunication/ProtonVPN.ProcessCommunication.EntityMapping/Vpn/VpnCredentialsMapper.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Proton AG
2+
* Copyright (c) 2025 Proton AG
33
*
44
* This file is part of ProtonVPN.
55
*
@@ -43,14 +43,18 @@ public VpnCredentialsIpcEntity Map(VpnCredentials leftEntity)
4343
Pem = leftEntity.ClientCertPem ?? string.Empty,
4444
ExpirationDateUtc = leftEntity.ClientCertificateExpirationDateUtc ?? DateTime.MinValue,
4545
},
46-
ClientKeyPair = _entityMapper.Map<AsymmetricKeyPair, AsymmetricKeyPairIpcEntity>(leftEntity.ClientKeyPair)
46+
ClientKeyPair = _entityMapper.Map<AsymmetricKeyPair, AsymmetricKeyPairIpcEntity>(leftEntity.ClientKeyPair),
47+
Username = leftEntity.Username,
48+
Password = leftEntity.Password,
4749
};
4850
}
4951

5052
public VpnCredentials Map(VpnCredentialsIpcEntity rightEntity)
5153
{
5254
return new(rightEntity.Certificate.Pem,
5355
rightEntity.Certificate.ExpirationDateUtc,
54-
_entityMapper.Map<AsymmetricKeyPairIpcEntity, AsymmetricKeyPair>(rightEntity.ClientKeyPair));
56+
_entityMapper.Map<AsymmetricKeyPairIpcEntity, AsymmetricKeyPair>(rightEntity.ClientKeyPair),
57+
rightEntity.Username,
58+
rightEntity.Password);
5559
}
5660
}

src/ProtonVPN.Common.Legacy/Vpn/VpnCredentials.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 Proton AG
2+
* Copyright (c) 2025 Proton AG
33
*
44
* This file is part of ProtonVPN.
55
*
@@ -28,21 +28,31 @@ public readonly struct VpnCredentials
2828
public VpnCredentials(
2929
string clientCertPem,
3030
DateTime? clientCertificateExpirationDateUtc,
31-
AsymmetricKeyPair clientKeyPair)
31+
AsymmetricKeyPair clientKeyPair,
32+
string username,
33+
string password)
3234
{
3335
Ensure.NotNull(clientKeyPair, nameof(clientKeyPair));
3436

3537
ClientCertPem = clientCertPem;
3638
ClientCertificateExpirationDateUtc = clientCertificateExpirationDateUtc;
3739
ClientKeyPair = clientKeyPair;
40+
Username = username;
41+
Password = password;
3842
}
3943

40-
public VpnCredentials(AsymmetricKeyPair clientKeyPair) : this(string.Empty, null, clientKeyPair)
44+
public VpnCredentials(AsymmetricKeyPair clientKeyPair) : this(string.Empty, null, clientKeyPair, string.Empty, string.Empty)
4145
{
4246
}
4347

48+
public VpnCredentials(AsymmetricKeyPair clientKeyPair, string username, string password) : this(string.Empty, null, clientKeyPair, username, password)
49+
{
50+
}
51+
52+
public string Username { get; }
53+
public string Password { get; }
54+
4455
public string ClientCertPem { get; }
4556
public DateTime? ClientCertificateExpirationDateUtc { get; }
46-
4757
public AsymmetricKeyPair ClientKeyPair { get; }
4858
}

src/ProtonVPN.Vpn/Management/ManagementClient.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,16 @@ private async void HandleMessage(ReceivedManagementMessage message)
170170
_disconnectAccepted = true;
171171
handled = true;
172172
}
173+
else if (message.IsUsernameNeeded)
174+
{
175+
await TrySend(_managementChannel.Messages.Username(_credentials.Username));
176+
handled = true;
177+
}
178+
else if (message.IsPasswordNeeded)
179+
{
180+
await TrySend(_managementChannel.Messages.Password(_credentials.Password));
181+
handled = true;
182+
}
173183
else if (message.IsControlMessage)
174184
{
175185
HandleControlMessage(message);

0 commit comments

Comments
 (0)