Skip to content

Commit a13f952

Browse files
committed
fix: opt-in tailscale vpn loop prevention
1 parent efb60ca commit a13f952

File tree

6 files changed

+48
-7
lines changed

6 files changed

+48
-7
lines changed

App/App.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public App()
9292

9393
services.AddSingleton<IDispatcherQueueManager>(_ => this);
9494
services.AddSingleton<IDefaultNotificationHandler>(_ => this);
95+
services.AddSingleton<ISettingsManager<CoderConnectSettings>, SettingsManager<CoderConnectSettings>>();
9596
services.AddSingleton<ICredentialBackend>(_ =>
9697
new WindowsCredentialBackend(WindowsCredentialBackend.CoderCredentialsTargetName));
9798
services.AddSingleton<ICredentialManager, CredentialManager>();
@@ -120,7 +121,6 @@ public App()
120121
// FileSyncListMainPage is created by FileSyncListWindow.
121122
services.AddTransient<FileSyncListWindow>();
122123

123-
services.AddSingleton<ISettingsManager<CoderConnectSettings>, SettingsManager<CoderConnectSettings>>();
124124
services.AddSingleton<IStartupManager, StartupManager>();
125125
// SettingsWindow views and view models
126126
services.AddTransient<SettingsViewModel>();

App/Models/Settings.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public class CoderConnectSettings : ISettings<CoderConnectSettings>
3434
/// </summary>
3535
public bool ConnectOnLaunch { get; set; }
3636

37+
/// <summary>
38+
/// When this is true Coder Connect will not attempt to protect against Tailscale loopback issues.
39+
/// </summary>
40+
public bool DisableTailscaleLoopProtection { get; set; }
41+
3742
/// <summary>
3843
/// CoderConnect current settings version. Increment this when the settings schema changes.
3944
/// In future iterations we will be able to handle migrations when the user has
@@ -46,17 +51,21 @@ public CoderConnectSettings()
4651
Version = VERSION;
4752

4853
ConnectOnLaunch = false;
54+
55+
DisableTailscaleLoopProtection = false;
4956
}
5057

51-
public CoderConnectSettings(int? version, bool connectOnLaunch)
58+
public CoderConnectSettings(int? version, bool connectOnLaunch, bool disableTailscaleLoopProtection)
5259
{
5360
Version = version ?? VERSION;
5461

5562
ConnectOnLaunch = connectOnLaunch;
63+
64+
DisableTailscaleLoopProtection = disableTailscaleLoopProtection;
5665
}
5766

5867
public CoderConnectSettings Clone()
5968
{
60-
return new CoderConnectSettings(Version, ConnectOnLaunch);
69+
return new CoderConnectSettings(Version, ConnectOnLaunch, DisableTailscaleLoopProtection);
6170
}
6271
}

App/Services/RpcController.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,18 @@ public interface IRpcController : IAsyncDisposable
6969
public class RpcController : IRpcController
7070
{
7171
private readonly ICredentialManager _credentialManager;
72+
private readonly ISettingsManager<CoderConnectSettings> _settingsManager;
7273

7374
private readonly RaiiSemaphoreSlim _operationLock = new(1, 1);
7475
private Speaker<ClientMessage, ServiceMessage>? _speaker;
7576

7677
private readonly RaiiSemaphoreSlim _stateLock = new(1, 1);
7778
private readonly RpcModel _state = new();
7879

79-
public RpcController(ICredentialManager credentialManager)
80+
public RpcController(ICredentialManager credentialManager, ISettingsManager<CoderConnectSettings> settingsManager)
8081
{
8182
_credentialManager = credentialManager;
83+
_settingsManager = settingsManager;
8284
}
8385

8486
public event EventHandler<RpcModel>? StateChanged;
@@ -156,6 +158,11 @@ public async Task StartVpn(CancellationToken ct = default)
156158
using var _ = await AcquireOperationLockNowAsync();
157159
AssertRpcConnected();
158160

161+
var coderConnectSettings = await _settingsManager.Read();
162+
var disableTailscaleLoopProtection = coderConnectSettings.DisableTailscaleLoopProtection;
163+
Debug.WriteLine(
164+
$"Starting VPN with DisableTailscaleLoopProtection={disableTailscaleLoopProtection}");
165+
159166
var credentials = _credentialManager.GetCachedCredentials();
160167
if (credentials.State != CredentialState.Valid)
161168
throw new RpcOperationException(

App/ViewModels/SettingsViewModel.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ public partial class SettingsViewModel : ObservableObject
1313
[ObservableProperty]
1414
public partial bool ConnectOnLaunch { get; set; }
1515

16+
[ObservableProperty]
17+
public partial bool DisableTailscaleLoopProtection { get; set; }
18+
1619
[ObservableProperty]
1720
public partial bool StartOnLoginDisabled { get; set; }
1821

@@ -31,6 +34,7 @@ public SettingsViewModel(ILogger<SettingsViewModel> logger, ISettingsManager<Cod
3134
_connectSettings = settingsManager.Read().GetAwaiter().GetResult();
3235
StartOnLogin = startupManager.IsEnabled();
3336
ConnectOnLaunch = _connectSettings.ConnectOnLaunch;
37+
DisableTailscaleLoopProtection = _connectSettings.DisableTailscaleLoopProtection;
3438

3539
// Various policies can disable the "Start on login" option.
3640
// We disable the option in the UI if the policy is set.
@@ -43,6 +47,21 @@ public SettingsViewModel(ILogger<SettingsViewModel> logger, ISettingsManager<Cod
4347
}
4448
}
4549

50+
partial void OnDisableTailscaleLoopProtectionChanged(bool oldValue, bool newValue)
51+
{
52+
if (oldValue == newValue)
53+
return;
54+
try
55+
{
56+
_connectSettings.DisableTailscaleLoopProtection = DisableTailscaleLoopProtection;
57+
_connectSettingsManager.Write(_connectSettings);
58+
}
59+
catch (Exception ex)
60+
{
61+
_logger.LogError($"Error saving Coder Connect {nameof(DisableTailscaleLoopProtection)} settings: {ex.Message}");
62+
}
63+
}
64+
4665
partial void OnConnectOnLaunchChanged(bool oldValue, bool newValue)
4766
{
4867
if (oldValue == newValue)
@@ -54,7 +73,7 @@ partial void OnConnectOnLaunchChanged(bool oldValue, bool newValue)
5473
}
5574
catch (Exception ex)
5675
{
57-
_logger.LogError($"Error saving Coder Connect settings: {ex.Message}");
76+
_logger.LogError($"Error saving Coder Connect {nameof(ConnectOnLaunch)} settings: {ex.Message}");
5877
}
5978
}
6079

App/Views/Pages/SettingsMainPage.xaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
>
4545
<ToggleSwitch IsOn="{x:Bind ViewModel.ConnectOnLaunch, Mode=TwoWay}" />
4646
</controls:SettingsCard>
47+
<controls:SettingsCard Description="This setting controls whether Coder Connect should bypass VPN loop preventation mechanism. Turn this ON only when dealing with a Coder deployment behind a corporate VPN."
48+
Header="Disable corporate VPN loop protection"
49+
HeaderIcon="{ui:FontIcon Glyph=&#xE8AF;}"
50+
>
51+
<ToggleSwitch IsOn="{x:Bind ViewModel.DisableTailscaleLoopProtection, Mode=TwoWay}" />
52+
</controls:SettingsCard>
4753
</StackPanel>
4854
</Grid>
4955
</ScrollViewer>

App/Views/SettingsWindow.xaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
xmlns:winuiex="using:WinUIEx"
1010
mc:Ignorable="d"
1111
Title="Coder Settings"
12-
Width="600" Height="350"
13-
MinWidth="600" MinHeight="350">
12+
Width="600" Height="450"
13+
MinWidth="600" MinHeight="450">
1414

1515
<Window.SystemBackdrop>
1616
<MicaBackdrop/>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy