diff --git a/DesktopEdge/App.xaml b/DesktopEdge/App.xaml
index 4137cd29..bcd9158d 100644
--- a/DesktopEdge/App.xaml
+++ b/DesktopEdge/App.xaml
@@ -149,5 +149,23 @@
+
+
+
diff --git a/DesktopEdge/MainWindow.xaml.cs b/DesktopEdge/MainWindow.xaml.cs
index 31a20849..c67c738d 100644
--- a/DesktopEdge/MainWindow.xaml.cs
+++ b/DesktopEdge/MainWindow.xaml.cs
@@ -68,8 +68,8 @@ namespace ZitiDesktopEdge {
ExpectedLogPathServices = Path.Combine(ExpectedLogPathRoot, "service", $"ziti-tunneler.log");
}
- private void IdentityMenu_OnMessage(string message) {
- ShowBlurbAsync(message, "");
+ async private void IdentityMenu_OnMessage(string message) {
+ await ShowBlurbAsync(message, "");
}
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e) {
@@ -105,14 +105,14 @@ namespace ZitiDesktopEdge {
/// The MFA Event
private void ServiceClient_OnMfaEvent(object sender, MfaEvent mfa) {
HideLoad();
- this.Dispatcher.Invoke(() => {
+ this.Dispatcher.Invoke(async () => {
if (mfa.Action == "enrollment_challenge") {
string url = HttpUtility.UrlDecode(mfa.ProvisioningUrl);
string secret = HttpUtility.ParseQueryString(url)["secret"];
this.IdentityMenu.Identity.MFAInfo.RecoveryCodes = mfa?.RecoveryCodes?.ToArray();
SetupMFA(this.IdentityMenu.Identity, url, secret);
} else if (mfa.Action == "auth_challenge") {
- ShowBlurbAsync("Setting Up auth_challenge", "");
+ await ShowBlurbAsync("Setting Up auth_challenge", "");
} else if (mfa.Action == "enrollment_verification") {
if (mfa.Successful) {
ShowMFARecoveryCodes(this.IdentityMenu.Identity);
@@ -127,7 +127,7 @@ namespace ZitiDesktopEdge {
} else if (mfa.Action == "enrollment_remove") {
// ShowBlurb("removed mfa: " + mfa.Successful, "");
} else {
- ShowBlurbAsync("Unexpected error when processing MFA", "");
+ await ShowBlurbAsync ("Unexpected error when processing MFA", "");
logger.Error("unexpected action: " + mfa.Action);
}
LoadIdentities(true);
@@ -172,9 +172,9 @@ namespace ZitiDesktopEdge {
/// Show the MFA Recovery Codes
///
/// The Ziti Identity to Authenticate
- public void ShowMFARecoveryCodes(ZitiIdentity identity) {
+ async public void ShowMFARecoveryCodes(ZitiIdentity identity) {
if (identity.MFAInfo!=null) {
- if (identity.MFAInfo.RecoveryCodes?.Length > 0) {
+ if (identity.MFAInfo.IsAuthenticated&& identity.MFAInfo.RecoveryCodes!=null) {
MFASetup.Opacity = 0;
MFASetup.Visibility = Visibility.Visible;
MFASetup.Margin = new Thickness(0, 0, 0, 0);
@@ -188,7 +188,7 @@ namespace ZitiDesktopEdge {
this.ShowMFA(IdentityMenu.Identity, 2);
}
} else {
- ShowBlurbAsync("MFA is not setup on this Identity", "");
+ await ShowBlurbAsync("MFA is not setup on this Identity", "");
}
}
@@ -232,7 +232,7 @@ namespace ZitiDesktopEdge {
///
/// Close the MFA Screen with animation
///
- private void DoClose(bool isComplete) {
+ async private void DoClose(bool isComplete) {
DoubleAnimation animation = new DoubleAnimation(0, TimeSpan.FromSeconds(.3));
ThicknessAnimation animateThick = new ThicknessAnimation(new Thickness(0, 0, 0, 0), TimeSpan.FromSeconds(.3));
animation.Completed += CloseComplete;
@@ -252,15 +252,11 @@ namespace ZitiDesktopEdge {
if (IdentityMenu.IsVisible) {
if (isComplete) {
if (MFASetup.Type == 2) {
- if (IdentityMenu.Identity.MFAInfo?.RecoveryCodes?.Length > 0) {
- ShowRecovery(IdentityMenu.Identity);
- } else {
- ShowBlurbAsync("You do not have anymore recovery codes", this.RECOVER);
- }
+ ShowRecovery(IdentityMenu.Identity);
} else if (MFASetup.Type == 3) {
IdentityMenu.Identity.IsMFAEnabled = false;
IdentityMenu.Identity.MFAInfo.IsAuthenticated = false;
- ShowBlurbAsync("MFA Disabled, Service Access Can Be Limited", "");
+ await ShowBlurbAsync("MFA Disabled, Service Access Can Be Limited", "");
} else if (MFASetup.Type == 4) {
ShowRecovery(IdentityMenu.Identity);
}
@@ -346,9 +342,15 @@ namespace ZitiDesktopEdge {
this.IdentityMenu.MainWindow = this;
SetNotifyIcon("white");
+ MFASetup.OnLoad += MFASetup_OnLoad;
IdentityMenu.OnMessage += IdentityMenu_OnMessage;
}
+ private void MFASetup_OnLoad(bool isComplete, string title, string message) {
+ if (isComplete) HideLoad();
+ else ShowLoad(title, message);
+ }
+
private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) {
if (notifyIcon != null) {
notifyIcon.Visible = false;
@@ -487,7 +489,8 @@ namespace ZitiDesktopEdge {
serviceClient.OnServiceEvent += ServiceClient_OnServiceEvent;
serviceClient.OnTunnelStatusEvent += ServiceClient_OnTunnelStatusEvent;
serviceClient.OnMfaEvent += ServiceClient_OnMfaEvent;
- serviceClient.OnLogLevelEvent += ServiceClient_OnLogLevelEvent;
+ serviceClient.OnLogLevelEvent += ServiceClient_OnLogLevelEvent;
+ serviceClient.OnBulkServiceEvent += ServiceClient_OnBulkServiceEvent;
Application.Current.Properties.Add("ServiceClient", serviceClient);
monitorClient = new MonitorClient();
@@ -521,6 +524,28 @@ namespace ZitiDesktopEdge {
Placement();
}
+ private void ServiceClient_OnBulkServiceEvent(object sender, BulkServiceEvent e) {
+ var found = identities.Find(id => id.Fingerprint == e.Fingerprint);
+ if (found == null) {
+ logger.Warn($"{e.Action} service event for {e.Fingerprint} but the provided identity fingerprint was not found!");
+ return;
+ } else {
+ foreach (var removed in e.RemovedServices) {
+ removeService(found, removed);
+ }
+ foreach (var added in e.AddedServices) {
+ addService(found, added);
+ }
+ LoadIdentities(false);
+ this.Dispatcher.Invoke(() => {
+ IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
+ if (deets.IsVisible) {
+ deets.UpdateView();
+ }
+ });
+ }
+ }
+
string nextVersionStr = null;
private void MonitorClient_OnReconnectFailure(object sender, object e) {
if (nextVersionStr == null) {
@@ -699,6 +724,9 @@ namespace ZitiDesktopEdge {
private void ServiceClient_OnClientDisconnected(object sender, object e) {
this.Dispatcher.Invoke(() => {
+ IdentityMenu.Visibility = Visibility.Collapsed;
+ MFASetup.Visibility = Visibility.Collapsed;
+ HideModal();
IdList.Children.Clear();
if (e != null) {
logger.Debug(e.ToString());
@@ -770,34 +798,20 @@ namespace ZitiDesktopEdge {
private void ServiceClient_OnServiceEvent(object sender, ServiceEvent e) {
if (e == null) return;
- Debug.WriteLine($"==== ServiceEvent : action:{e.Action} fingerprint:{e.Fingerprint} name:{e.Service.Name} ");
+ logger.Debug($"==== ServiceEvent : action:{e.Action} fingerprint:{e.Fingerprint} name:{e.Service.Name} ");
+ var found = identities.Find(id => id.Fingerprint == e.Fingerprint);
+ if (found == null) {
+ logger.Debug($"{e.Action} service event for {e.Service.Name} but the provided identity fingerprint {e.Fingerprint} is not found!");
+ return;
+ }
+
+ if (e.Action == "added") {
+ addService(found, e.Service);
+ } else {
+ removeService(found, e.Service);
+ }
+ LoadIdentities(false);
this.Dispatcher.Invoke(() => {
- var found = identities.Find(id => id.Fingerprint == e.Fingerprint);
-
- if (found == null) {
- Debug.WriteLine($"{e.Action} service event for {e.Service.Name} but the provided identity fingerprint {e.Fingerprint} is not found!");
- return;
- }
-
- if (e.Action == "added") {
- ZitiService zs = new ZitiService(e.Service);
- var svc = found.Services.Find(s => s.Name == zs.Name);
- if (svc == null) {
- found.Services.Add(zs);
- if (zs.HasFailingPostureCheck()) {
- found.HasServiceFailingPostureCheck = true;
- if (zs.PostureChecks.Any(p => !p.IsPassing && p.QueryType == "MFA")) {
- found.MFAInfo.IsAuthenticated = false;
- }
- }
- } else {
- logger.Debug("the service named " + zs.Name + " is already accounted for on this identity.");
- }
- } else {
- logger.Debug("removing the service named: " + e.Service.Name);
- found.Services.RemoveAll(s => s.Name == e.Service.Name);
- }
- LoadIdentities(false);
IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
if (deets.IsVisible) {
deets.UpdateView();
@@ -805,6 +819,27 @@ namespace ZitiDesktopEdge {
});
}
+ private void addService(ZitiIdentity found, Service added) {
+ ZitiService zs = new ZitiService(added);
+ var svc = found.Services.Find(s => s.Name == zs.Name);
+ if (svc == null) {
+ found.Services.Add(zs);
+ if (zs.HasFailingPostureCheck()) {
+ found.HasServiceFailingPostureCheck = true;
+ if (zs.PostureChecks.Any(p => !p.IsPassing && p.QueryType == "MFA")) {
+ found.MFAInfo.IsAuthenticated = false;
+ }
+ }
+ } else {
+ logger.Debug("the service named " + zs.Name + " is already accounted for on this identity.");
+ }
+ }
+
+ private void removeService(ZitiIdentity found, Service removed) {
+ logger.Debug("removing the service named: {0}", removed.Name);
+ found.Services.RemoveAll(s => s.Name == removed.Name);
+ }
+
private void ServiceClient_OnTunnelStatusEvent(object sender, TunnelStatusEvent e) {
if (e == null) return; //just skip it for now...
logger.Debug($"==== TunnelStatusEvent: ");
@@ -889,6 +924,9 @@ namespace ZitiDesktopEdge {
if (!Application.Current.Properties.Contains("dns")) {
Application.Current.Properties.Add("dns", status?.IpInfo?.DNS);
}
+ if (!Application.Current.Properties.Contains("dnsenabled")) {
+ Application.Current.Properties.Add("dnsenabled", status?.AddDns);
+ }
foreach (var id in status.Identities) {
updateViewWithIdentity(id);
diff --git a/DesktopEdge/Models/MessageCount.cs b/DesktopEdge/Models/MessageCount.cs
index c4f76a72..a006f4a7 100644
--- a/DesktopEdge/Models/MessageCount.cs
+++ b/DesktopEdge/Models/MessageCount.cs
@@ -9,7 +9,7 @@ namespace ZitiDesktopEdge.Models {
public int Total { get; set; }
public string Message { get; set; }
- public string ToString() {
+ public override string ToString() {
return Total + " " + Message;
}
}
diff --git a/DesktopEdge/Properties/AssemblyInfo.cs b/DesktopEdge/Properties/AssemblyInfo.cs
index 0ad08d87..ec3cefc3 100644
--- a/DesktopEdge/Properties/AssemblyInfo.cs
+++ b/DesktopEdge/Properties/AssemblyInfo.cs
@@ -50,6 +50,6 @@ using System.Windows;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.2.0")]
-[assembly: AssemblyVersion("1.9.2.0")]
-[assembly: AssemblyFileVersion("1.9.2.0")]
+// [assembly: AssemblyVersion("1.9.3.0")]
+[assembly: AssemblyVersion("1.9.3.0")]
+[assembly: AssemblyFileVersion("1.9.3.0")]
diff --git a/DesktopEdge/Views/Controls/Toggler.xaml.cs b/DesktopEdge/Views/Controls/Toggler.xaml.cs
index db20d222..dd0dc4f8 100644
--- a/DesktopEdge/Views/Controls/Toggler.xaml.cs
+++ b/DesktopEdge/Views/Controls/Toggler.xaml.cs
@@ -54,6 +54,13 @@ namespace ZitiDesktopEdge {
}
}
}
+
+ public void Toggle() {
+ Enabled = !Enabled;
+ if (OnToggled != null) {
+ OnToggled(Enabled);
+ }
+ }
private void OnToggle(object sender, RoutedEventArgs e) {
e.Handled = true;
diff --git a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml
index fdef3fd4..a3d74706 100644
--- a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml
+++ b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml
@@ -12,7 +12,7 @@
-
+
@@ -24,22 +24,31 @@
+
-
+
+
diff --git a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
index fb7ef1a9..1b75ed8e 100644
--- a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
+++ b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
@@ -115,5 +115,17 @@ namespace ZitiDesktopEdge {
private void MFAAuthenticate(object sender, MouseButtonEventArgs e) {
this.Authenticate?.Invoke(_identity);
}
+
+ private void ToggledSwitch(object sender, MouseButtonEventArgs e) {
+ ToggleSwitch.Toggle();
+ }
+
+ private void DoMFAOrOpen(object sender, MouseButtonEventArgs e) {
+ if (MfaRequired.Visibility==Visibility.Visible) {
+ MFAAuthenticate(sender, e);
+ } else {
+ OpenDetails(sender, e);
+ }
+ }
}
}
diff --git a/DesktopEdge/Views/Screens/IdentityDetails.xaml b/DesktopEdge/Views/Screens/IdentityDetails.xaml
index 748816b4..408e801a 100644
--- a/DesktopEdge/Views/Screens/IdentityDetails.xaml
+++ b/DesktopEdge/Views/Screens/IdentityDetails.xaml
@@ -50,7 +50,7 @@
-
+
@@ -78,10 +78,41 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+ Name
+ Address
+ Protocol
+ Port
+
+
+
+
+
+
+ Asc
+ Desc
+
+
+
+
+
diff --git a/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs b/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs
index f15ce065..ebaa8140 100644
--- a/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs
+++ b/DesktopEdge/Views/Screens/IdentityDetails.xaml.cs
@@ -35,6 +35,10 @@ namespace ZitiDesktopEdge {
public event OnAuthenticate Authenticate;
public delegate void OnRecovery(ZitiIdentity identity);
public event OnRecovery Recovery;
+ public int Page = 1;
+ public int PerPage = 50;
+ public string SortBy = "Name";
+ public string SortWay = "Asc";
internal MainWindow MainWindow { get; set; }
@@ -53,6 +57,11 @@ namespace ZitiDesktopEdge {
set {
_identity = value;
this.IdDetailToggle.Enabled = _identity.IsEnabled;
+ Page = 1;
+ SortBy = "Name";
+ SortWay = "Asc";
+ SortByField.SelectedIndex = 0;
+ SortWayField.SelectedIndex = 0;
UpdateView();
IdentityArea.Opacity = 1.0;
IdentityArea.Visibility = Visibility.Visible;
@@ -117,17 +126,45 @@ namespace ZitiDesktopEdge {
IdentityMFA.RecoveryButton.Visibility = Visibility.Collapsed;
}
ServiceList.Children.Clear();
+ PageSortArea.Visibility = Visibility.Collapsed;
if (_identity.Services.Count>0) {
- foreach(var zitiSvc in _identity.Services.OrderBy(s => s.Name.ToLower())) {
- if (zitiSvc.Name.ToLower().IndexOf(filter.ToLower()) >=0||zitiSvc.ToString().ToLower().IndexOf(filter.ToLower()) >=0) {
- Logger.Trace("painting: " + zitiSvc.Name);
- ServiceInfo info = new ServiceInfo();
- info.Info = zitiSvc;
- info.OnMessage += Info_OnMessage;
- info.OnDetails += ShowDetails;
- ServiceList.Children.Add(info);
+ PageSortArea.Visibility = Visibility.Visible;
+ int index = 0;
+ int total = 0;
+ ZitiService[] services = new ZitiService[0];
+ if (SortBy == "Name") services = _identity.Services.OrderBy(s => s.Name.ToLower()).ToArray();
+ else if (SortBy == "Address") services = _identity.Services.OrderBy(s => s.Addresses.ToString()).ToArray();
+ else if (SortBy == "Protocol") services = _identity.Services.OrderBy(s => s.Protocols.ToString()).ToArray();
+ else if (SortBy == "Port") services = _identity.Services.OrderBy(s => s.Ports.ToString()).ToArray();
+ if (SortWay == "Desc") services = services.Reverse().ToArray();
+ int startIndex = (Page - 1) * PerPage;
+ for (int i= startIndex; i= 0 || zitiSvc.ToString().ToLower().IndexOf(filter.ToLower()) >= 0) {
+ Logger.Trace("painting: " + zitiSvc.Name);
+ ServiceInfo info = new ServiceInfo();
+ info.Info = zitiSvc;
+ info.OnMessage += Info_OnMessage;
+ info.OnDetails += ShowDetails;
+ ServiceList.Children.Add(info);
+ index++;
+ }
}
}
+
+ if (Page==1) {
+ Pages.Items.Clear();
+ int totalPages = (total / PerPage) + 1;
+ for (int i = 1; i <= totalPages; i++) {
+ ComboBoxItem item = new ComboBoxItem();
+ if (i == Page) item.IsSelected = true;
+ item.Content = i.ToString();
+ Pages.Items.Add(item);
+ }
+ }
+
double newHeight = MainHeight - 330;
ServiceRow.Height = new GridLength((double)newHeight);
MainDetailScroll.MaxHeight = newHeight;
@@ -326,5 +363,36 @@ namespace ZitiDesktopEdge {
private void AuthFromMessage(object sender, MouseButtonEventArgs e) {
this.Authenticate.Invoke(this.Identity);
}
+
+ private void Pages_SelectionChanged(object sender, SelectionChangedEventArgs e) {
+ ComboBoxItem selected = (ComboBoxItem)Pages.SelectedValue;
+ if (selected!=null) {
+ int value = Int32.Parse(selected.Content.ToString());
+ if (value!=Page) {
+ Page = value;
+ UpdateView();
+ }
+ }
+ }
+
+ private void SortByField_SelectionChanged(object sender, SelectionChangedEventArgs e) {
+ ComboBoxItem selected = (ComboBoxItem)SortByField.SelectedValue;
+ if (selected != null && selected.Content!=null) {
+ if (selected.Content.ToString()!=SortBy) {
+ SortBy = selected.Content.ToString();
+ UpdateView();
+ }
+ }
+ }
+
+ private void SortWayField_SelectionChanged(object sender, SelectionChangedEventArgs e) {
+ ComboBoxItem selected = (ComboBoxItem)SortWayField.SelectedValue;
+ if (selected != null && selected.Content != null) {
+ if (selected.Content.ToString() != SortWay) {
+ SortWay = selected.Content.ToString();
+ UpdateView();
+ }
+ }
+ }
}
}
diff --git a/DesktopEdge/Views/Screens/MFAScreen.xaml b/DesktopEdge/Views/Screens/MFAScreen.xaml
index 26d15bcf..d71f88d2 100644
--- a/DesktopEdge/Views/Screens/MFAScreen.xaml
+++ b/DesktopEdge/Views/Screens/MFAScreen.xaml
@@ -13,11 +13,19 @@
-
+
+
+
+
+
+
+
+
+
@@ -51,7 +59,7 @@
-
+
-
-
-
-
-
-
-
-
+
-
+
+
diff --git a/DesktopEdge/Views/Screens/MFAScreen.xaml.cs b/DesktopEdge/Views/Screens/MFAScreen.xaml.cs
index 9563833d..e626d46d 100644
--- a/DesktopEdge/Views/Screens/MFAScreen.xaml.cs
+++ b/DesktopEdge/Views/Screens/MFAScreen.xaml.cs
@@ -31,6 +31,8 @@ namespace ZitiDesktopEdge {
public partial class MFAScreen : UserControl {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+ public delegate void LoadEvent(bool isComplete, string title, string message);
+ public event LoadEvent OnLoad;
public delegate void CloseAction(bool isComplete);
public event CloseAction OnClose;
private string _url = "";
@@ -83,10 +85,14 @@ namespace ZitiDesktopEdge {
this._identity = identity;
MFAImage.Visibility = Visibility.Visible;
SecretCode.Visibility = Visibility.Collapsed;
+ CloseBlack.Visibility = Visibility.Visible;
+ CloseWhite.Visibility = Visibility.Collapsed;
SecretButton.Content = "Show Secret";
IdName.Content = identity.Name;
Logger.Debug($"MFA Url: {url}");
-
+ AuthBrush.Visibility = Visibility.Collapsed;
+ MainBrush.Visibility = Visibility.Visible;
+
MFAImage.Source = CreateQRFromUrl(url);
SecretCode.Text = secret;
@@ -107,24 +113,39 @@ namespace ZitiDesktopEdge {
MFARecoveryArea.Visibility = Visibility.Visible;
RecoveryList.Children.Clear();
_codes = codes;
+ AuthBrush.Visibility = Visibility.Collapsed;
+ MainBrush.Visibility = Visibility.Visible;
+ CloseBlack.Visibility = Visibility.Visible;
+ CloseWhite.Visibility = Visibility.Collapsed;
MFAArea.Height = 380;
- for (int i=0; i0) {
+ for (int i = 0; i < codes.Length; i++) {
+ TextBox label = new TextBox();
+ label.Text = codes[i];
+ label.BorderThickness = new Thickness(0);
+ label.Background = new SolidColorBrush();
+ label.Background.Opacity = 0;
+ label.HorizontalAlignment = HorizontalAlignment.Center;
+ label.HorizontalContentAlignment = HorizontalAlignment.Center;
+ label.VerticalAlignment = VerticalAlignment.Center;
+ label.VerticalContentAlignment = VerticalAlignment.Center;
+ RecoveryList.Children.Add(label);
+ }
+ RecoveryList.Visibility = Visibility.Visible;
+ NoRecovery.Visibility = Visibility.Collapsed;
+ } else {
+ RecoveryList.Visibility = Visibility.Collapsed;
+ NoRecovery.Visibility = Visibility.Visible;
}
}
public void ShowMFA(ZitiIdentity identity, int type) {
this.Type = type;
AuthCode.Text = "";
+ AuthBrush.Visibility = Visibility.Visible;
+ MainBrush.Visibility = Visibility.Collapsed;
+ CloseBlack.Visibility = Visibility.Collapsed;
+ CloseWhite.Visibility = Visibility.Visible;
this._identity = identity;
MFASetupArea.Visibility = Visibility.Collapsed;
MFARecoveryArea.Visibility = Visibility.Collapsed;
@@ -152,21 +173,6 @@ namespace ZitiDesktopEdge {
}
}
- private void ToggleRecovery(object sender, MouseButtonEventArgs e) {
- AuthCode.Text = "";
- if (AuthCode.MaxLength==6) {
- GenerateMFACodes(null, null);
- AuthCode.MaxLength = 8;
- ToggleType.Content = "Use Auth Code";
- AuthSubTitle.Content = "Enter a recovery code";
- AuthCode.Focus();
- } else {
- AuthCode.MaxLength = 6;
- ToggleType.Content = "Use Recovery Code";
- AuthSubTitle.Content = "Enter your authorization code";
- AuthCode.Focus();
- }
- }
async private void ReturnMFACodes(object sender, MouseButtonEventArgs e) {
DataClient serviceClient = serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
string code = AuthCode.Text;
@@ -214,17 +220,14 @@ namespace ZitiDesktopEdge {
}
}
- async private void DoAuthenticate(object sender, MouseButtonEventArgs e) {
+ async private void DoAuthenticate() {
if (!this._executing) {
+
this._executing = true;
string code = AuthCode.Text;
- if (AuthCode.MaxLength == 8) {
- if (code.Length != 8) this.ShowError("You must enter a valid recovery code");
- } else {
- if (code.Length != 6) this.ShowError("You must enter a valid code");
- }
DataClient serviceClient = (DataClient)Application.Current.Properties["ServiceClient"];
+ this.OnLoad?.Invoke(false, "Authentication", "One Moment Please...");
if (this.Type == 1) {
SvcResponse authResult = await serviceClient.AuthMFA(this._identity.Fingerprint, code);
if (authResult?.Code != 0) {
@@ -238,6 +241,7 @@ namespace ZitiDesktopEdge {
this.OnClose?.Invoke(true);
this._executing = false;
}
+ this.OnLoad?.Invoke(true, "", "");
} else if (this.Type == 2) {
MfaRecoveryCodesResponse codeResponse = await serviceClient.ReturnMFACodes(this._identity.Fingerprint, code);
if (codeResponse?.Code != 0) {
@@ -250,6 +254,7 @@ namespace ZitiDesktopEdge {
this.OnClose?.Invoke(true);
this._executing = false;
}
+ this.OnLoad?.Invoke(true, "", "");
} else if (this.Type == 3) {
SvcResponse authResult = await serviceClient.RemoveMFA(this._identity.Fingerprint, code);
if (authResult?.Code != 0) {
@@ -261,6 +266,7 @@ namespace ZitiDesktopEdge {
this.OnClose?.Invoke(true);
this._executing = false;
}
+ this.OnLoad?.Invoke(true, "", "");
} else if (this.Type == 4) {
MfaRecoveryCodesResponse codeResponse = await serviceClient.GenerateMFACodes(this._identity.Fingerprint, code);
if (codeResponse?.Code != 0) {
@@ -273,6 +279,7 @@ namespace ZitiDesktopEdge {
this.OnClose?.Invoke(true);
this._executing = false;
}
+ this.OnLoad?.Invoke(true, "", "");
}
}
}
@@ -301,7 +308,7 @@ namespace ZitiDesktopEdge {
private void AuthCode_KeyUp(object sender, KeyEventArgs e) {
if (e.Key == Key.Return) {
- DoAuthenticate(sender, null);
+ DoAuthenticate();
}
}
}
diff --git a/DesktopEdge/Views/Screens/MainMenu.xaml.cs b/DesktopEdge/Views/Screens/MainMenu.xaml.cs
index 95ce1a79..aeb5726e 100644
--- a/DesktopEdge/Views/Screens/MainMenu.xaml.cs
+++ b/DesktopEdge/Views/Screens/MainMenu.xaml.cs
@@ -230,7 +230,7 @@ namespace ZitiDesktopEdge {
ConfigIp.Value = Application.Current.Properties["ip"]?.ToString();
ConfigSubnet.Value = Application.Current.Properties["subnet"]?.ToString();
ConfigMtu.Value = Application.Current.Properties["mtu"]?.ToString();
- ConfigDns.Value = Application.Current.Properties["dns"]?.ToString();
+ ConfigDns.Value = (bool)Application.Current.Properties["dnsenabled"] ? Application.Current.Properties["dns"]?.ToString() : "disabled";
} else if (menuState == "Identities") {
MenuTitle.Content = "Identities";
IdListScrollView.Visibility = Visibility.Visible;
diff --git a/DesktopEdge/ZitiDesktopEdge.csproj b/DesktopEdge/ZitiDesktopEdge.csproj
index fd06e0a6..b406e57b 100644
--- a/DesktopEdge/ZitiDesktopEdge.csproj
+++ b/DesktopEdge/ZitiDesktopEdge.csproj
@@ -91,6 +91,7 @@
..\packages\NLog.4.7.8\lib\net45\NLog.dll
+
..\packages\QRCoder.1.4.1\lib\net40\QRCoder.dll
diff --git a/Installer/ZitiDesktopEdge.aip b/Installer/ZitiDesktopEdge.aip
index 31f61afb..fff0961b 100644
--- a/Installer/ZitiDesktopEdge.aip
+++ b/Installer/ZitiDesktopEdge.aip
@@ -23,10 +23,10 @@
-
+
-
+
diff --git a/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs b/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
index 2d9ade78..c64191bc 100644
--- a/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
+++ b/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
@@ -264,7 +264,11 @@ namespace ZitiDesktopEdge.DataStructures {
public int Prefix { get; set; }
public override string ToString() {
- return Hostname;
+ if (IsHost) {
+ return Hostname;
+ } else {
+ return IP + "/" + Prefix;
+ }
}
}
@@ -333,6 +337,7 @@ namespace ZitiDesktopEdge.DataStructures {
public string LogLevel { get; set; }
public ServiceVersion ServiceVersion { get; set; }
+ public bool AddDns { get; set; }
public void Dump(System.IO.TextWriter writer)
{
@@ -408,12 +413,17 @@ namespace ZitiDesktopEdge.DataStructures {
public List Identities { get; set; }
}
- public class ServiceEvent : ActionEvent
- {
+ public class ServiceEvent : ActionEvent {
public string Fingerprint { get; set; }
public Service Service { get; set; }
}
+ public class BulkServiceEvent : ActionEvent {
+ public string Fingerprint { get; set; }
+ public List AddedServices { get; set; }
+ public List RemovedServices { get; set; }
+ }
+
public class IdentityEvent : ActionEvent
{
public Identity Id { get; set; }
diff --git a/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs b/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs
index 8e628be6..af87b68d 100644
--- a/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs
+++ b/ZitiDesktopEdge.Client/ServiceClient/DataClient.cs
@@ -35,6 +35,7 @@ namespace ZitiDesktopEdge.ServiceClient {
public event EventHandler OnServiceEvent;
public event EventHandler OnLogLevelEvent;
public event EventHandler OnMfaEvent;
+ public event EventHandler OnBulkServiceEvent;
protected override void ShutdownEvent(StatusEvent e) {
Logger.Debug("Clean shutdown detected from ziti");
@@ -57,12 +58,15 @@ namespace ZitiDesktopEdge.ServiceClient {
protected virtual void ServiceEvent(ServiceEvent e) {
OnServiceEvent?.Invoke(this, e);
}
-
+
+ protected virtual void BulkServiceEvent(BulkServiceEvent e) {
+ OnBulkServiceEvent?.Invoke(this, e);
+ }
+
protected virtual void LogLevelEvent(LogLevelEvent e) {
OnLogLevelEvent?.Invoke(this, e);
}
-
protected virtual void MfaEvent(MfaEvent e) {
OnMfaEvent?.Invoke(this, e);
}
@@ -199,21 +203,6 @@ namespace ZitiDesktopEdge.ServiceClient {
return;
}
- async public Task SetLogLevelAsync(LogLevelEnum level) {
- try {
- await sendAsync(new SetLogLevelFunction(Enum.GetName(level.GetType(), level)));
- SvcResponse resp = await readAsync(ipcReader);
- return;
- } catch (Exception ioe) {
- //almost certainly a problem with the pipe - recreate the pipe...
- //setupPipe();
- //throw ioe;
- Logger.Error(ioe, "Unexpected error");
- CommunicationError(ioe);
- }
- return;
- }
-
async public Task IdentityOnOffAsync(string fingerprint, bool onOff) {
try {
await sendAsync(new IdentityToggleFunction(fingerprint, onOff));
@@ -351,6 +340,14 @@ namespace ZitiDesktopEdge.ServiceClient {
ServiceEvent(svc);
}
break;
+ case "bulkservice":
+ //dbg comment Logger.Warn("BULKSERVICE EVENT: \n" + respAsString);
+ BulkServiceEvent bsvc = serializer.Deserialize(jsonReader);
+
+ if (bsvc != null) {
+ BulkServiceEvent(bsvc);
+ }
+ break;
case "logLevel":
LogLevelEvent ll = serializer.Deserialize(jsonReader);
diff --git a/ZitiUpdateService/Properties/AssemblyInfo.cs b/ZitiUpdateService/Properties/AssemblyInfo.cs
index 8c145f2d..6c15d9ab 100644
--- a/ZitiUpdateService/Properties/AssemblyInfo.cs
+++ b/ZitiUpdateService/Properties/AssemblyInfo.cs
@@ -30,6 +30,6 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.9.2.0")]
-[assembly: AssemblyVersion("1.9.2.0")]
-[assembly: AssemblyFileVersion("1.9.2.0")]
+// [assembly: AssemblyVersion("1.9.3.0")]
+[assembly: AssemblyVersion("1.9.3.0")]
+[assembly: AssemblyFileVersion("1.9.3.0")]
diff --git a/release-notes.md b/release-notes.md
index d291aec5..67b66a3f 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,3 +1,36 @@
+# Release 1.9.3
+
+## What's New
+* Page Service List
+* Sort Service on Identity Details Page
+* Consistent UX for MFA Screens
+
+## Other changes:
+* Service to UI interaction is now with one bulk update of services instead of one event per service update
+* Added a configuration option to control if DNS is applied to the TUN. Some users are having issues with NRPT-only working. For now we'll add a boolean that allows the user to control if DNS should be added to the TUN
+
+## Bugs fixed:
+* none
+
+## Dependency Updates
+* none
+
+# Release 1.9.3
+
+## What's New
+* Page Service List
+* Sort Service on Identity Details Page
+* Consistent UX for MFA Screens
+
+## Other changes:
+* Service to UI interaction is now with one bulk update of services instead of one event per service update
+
+## Bugs fixed:
+* none
+
+## Dependency Updates
+* none
+
# Release 1.9.2
## What's New
diff --git a/service/attach.bat b/service/attach.bat
new file mode 100644
index 00000000..8d7607dc
--- /dev/null
+++ b/service/attach.bat
@@ -0,0 +1,7 @@
+@echo off
+powershell "Get-Process | where -Property Name -eq "ziti-tunnel" | select -ExpandProperty id" > zid
+set /p zid= < zid
+del zid
+echo %zid%
+
+"c:\Program Files\JetBrains\GoLand 2020.1.1\plugins\go\lib\dlv\windows\dlv.exe" attach %zid% --headless --log --only-same-user=false --api-version=2 --accept-multiclient --listen=localhost:50000
diff --git a/service/cziti/sdk.c b/service/cziti/sdk.c
index eff88112..251cec2f 100644
--- a/service/cziti/sdk.c
+++ b/service/cziti/sdk.c
@@ -151,35 +151,6 @@ dns_manager* get_dns_mgr_from_c() {
return &dns_mgr_c;
}
-/* functions allowing go to iterate tunneleed_service_t* */
-protocol_t* stailq_first_protocol(tunneled_service_t* ts) {
- if(ts == NULL || ts->intercept == NULL ) {
- return NULL;
- }
- return STAILQ_FIRST(&ts->intercept->protocols);
-}
-address_t* stailq_first_address(tunneled_service_t* ts) {
- if(ts == NULL || ts->intercept == NULL ) {
- return NULL;
- }
- return STAILQ_FIRST(&ts->intercept->addresses);
-}
-port_range_t* stailq_first_port_range(tunneled_service_t* ts) {
- if(ts == NULL || ts->intercept == NULL ) {
- return NULL;
- }
- return STAILQ_FIRST(&ts->intercept->port_ranges);
-}
-protocol_t* stailq_next_protocol(protocol_t* cur) {
- return STAILQ_NEXT(cur, entries);
-}
-address_t* stailq_next_address(address_t* cur) {
- return STAILQ_NEXT(cur, entries);
-}
-port_range_t* stailq_next_port_range(port_range_t* cur) {
- return STAILQ_NEXT(cur, entries);
-}
-
char* ziti_char_array_get(char** arr, int idx) {
return arr ? arr[idx] : NULL;
}
diff --git a/service/cziti/sdk.go b/service/cziti/sdk.go
index 28b01c73..62a44bbe 100644
--- a/service/cziti/sdk.go
+++ b/service/cziti/sdk.go
@@ -41,37 +41,28 @@ void ziti_dump_to_file(void *ctx, char* outputPath);
int ziti_dump_to_log(void *ctx, void* stringsBuilder);
void* stailq_first_forgo(void* entries);
-protocol_t* stailq_first_protocol(tunneled_service_t* ts);
-address_t* stailq_first_address(tunneled_service_t* ts);
-port_range_t* stailq_first_port_range(tunneled_service_t* ts);
-
-protocol_t* stailq_next_protocol(protocol_t* cur);
-address_t* stailq_next_address(address_t* cur);
-port_range_t* stailq_next_port_range(port_range_t* cur);
-
*/
import "C"
import (
+ "encoding/json"
"errors"
- "github.com/openziti/desktop-edge-win/service/windns"
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/api"
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/dto"
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/util/logging"
+ "net"
"os"
"strings"
"sync"
"unsafe"
)
-const (
- ADDED = "added"
- REMOVED = "removed"
-)
-
var log = logging.Logger()
var noFileLog = logging.NoFilenameLogger()
var Version dto.ServiceVersion
-var ServiceChanges = make(chan dto.ServiceEvent, 256)
+var BulkServiceChanges = make(chan BulkServiceChange, 32)
+
+var cCfgZitiTunnelerClientV1 = C.CString("ziti-tunneler-client.v1")
+var cCfgInterceptV1 = C.CString("intercept.v1")
type sdk struct {
libuvCtx *C.libuv_ctx
@@ -81,6 +72,13 @@ type ServiceChange struct {
Service *ZService
ZitiContext *ZIdentity
}
+type BulkServiceChange struct {
+ Fingerprint string
+ HostnamesToAdd map[string]bool
+ HostnamesToRemove map[string]bool
+ ServicesToRemove []*dto.Service
+ ServicesToAdd []*dto.Service
+}
var _impl sdk
@@ -150,54 +148,54 @@ func NewZid(statusChange func(int)) *ZIdentity {
return zid
}
-func (c *ZIdentity) GetMetrics() (int64, int64, bool) {
- if c == nil {
+func (zid *ZIdentity) GetMetrics() (int64, int64, bool) {
+ if zid == nil {
return 0, 0, false
}
- if unsafe.Pointer(c.czctx) == C.NULL {
- log.Debugf("ziti context is still null. the identity is probably not initialized yet: %s", c.Fingerprint)
+ if unsafe.Pointer(zid.czctx) == C.NULL {
+ log.Debugf("ziti context is still null. the identity is probably not initialized yet: %s", zid.Fingerprint)
return 0, 0, false
}
var up, down C.double
- C.ziti_get_transfer_rates(c.czctx, &up, &down)
+ C.ziti_get_transfer_rates(zid.czctx, &up, &down)
return int64(up), int64(down), true
}
-func (c *ZIdentity) UnsafePointer() unsafe.Pointer {
- return unsafe.Pointer(c.czctx)
+func (zid *ZIdentity) UnsafePointer() unsafe.Pointer {
+ return unsafe.Pointer(zid.czctx)
}
-func (c *ZIdentity) AsKey() string {
+func (zid *ZIdentity) AsKey() string {
return "marker askey"
}
-func (c *ZIdentity) Status() (int, error) {
- return c.status, c.statusErr
+func (zid *ZIdentity) Status() (int, error) {
+ return zid.status, zid.statusErr
}
-func (c *ZIdentity) setVersionFromId() string {
- if len(c.Version) > 0 {
- return c.Version
+func (zid *ZIdentity) setVersionFromId() string {
+ if len(zid.Version) > 0 {
+ return zid.Version
}
- c.Version = ""
- if c != nil {
- if c.czctx != nil {
- v1 := C.ziti_get_controller_version(c.czctx)
+ zid.Version = ""
+ if zid != nil {
+ if zid.czctx != nil {
+ v1 := C.ziti_get_controller_version(zid.czctx)
return C.GoString(v1.version)
}
}
- return c.Version
+ return zid.Version
}
-func (c *ZIdentity) setNameFromId() string {
- if len(c.Name) > 0 {
- return c.Name
+func (zid *ZIdentity) setNameFromId() string {
+ if len(zid.Name) > 0 {
+ return zid.Name
}
- c.Name = ""
- if c != nil {
- if c.czid != nil {
- if c.czid.name != nil {
- c.Name = C.GoString(c.czid.name)
+ zid.Name = ""
+ if zid != nil {
+ if zid.czid != nil {
+ if zid.czid.name != nil {
+ zid.Name = C.GoString(zid.czid.name)
} else {
log.Debug("in Name - c.zid.name was nil")
}
@@ -207,12 +205,12 @@ func (c *ZIdentity) setNameFromId() string {
} else {
log.Debug("in Name - c was nil")
}
- return c.Name
+ return zid.Name
}
-func (c *ZIdentity) Tags() []string {
- if c.czctx != nil && c.czid != nil {
- C.c_mapiter(&c.czid.tags)
+func (zid *ZIdentity) Tags() []string {
+ if zid.czctx != nil && zid.czid != nil {
+ C.c_mapiter(&zid.czid.tags)
/*
it := C.model_map_iterator(&c.zid.tags)
for {
@@ -230,11 +228,11 @@ func (c *ZIdentity) Tags() []string {
return nil
}
-func (c *ZIdentity) Controller() string {
- if c.czctx != nil {
- return C.GoString(C.ziti_get_controller(c.czctx))
+func (zid *ZIdentity) Controller() string {
+ if zid.czctx != nil {
+ return C.GoString(C.ziti_get_controller(zid.czctx))
}
- return C.GoString(c.Options.controller)
+ return C.GoString(zid.Options.controller)
}
func (zid *ZIdentity) Shutdown() {
@@ -253,24 +251,84 @@ func doZitiShutdown(async *C.uv_async_t) {
C.ziti_shutdown(ctx)
}
-func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, zid *ZIdentity) []dto.Address {
+type clientV1Cfg struct {
+ //{"addresses":["eth0.ziti.ranged","eth0.second","eth0.third"],"portRanges":[{"high":80,"low":80},{"high":443,"low":443}],"protocols":["tcp"]}
+ Addresses []string `json:"addresses"`
+ PortRanges []dto.PortRange `json:"portRanges"`
+ Protocols []string `json:"protocols"`
+}
+type v1ClientCfg struct {
+ //{"hostname":"192.168.15.15","port":80}
+ Hostname string `json:"hostname"`
+ Port int `json:"port"`
+}
+
+func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, zid *ZIdentity) *dto.Service {
if zid == nil {
log.Errorf("in serviceCB with nil zid??? ")
- return make([]dto.Address, 0)
+ return nil
}
name := C.GoString(service.name)
svcId := C.GoString(service.id)
log.Debugf("============ INSIDE serviceCB - status: %s:%s - %v, %v ============", name, svcId, status, service.perm_flags)
- ts := C.ziti_sdk_c_on_service(ziti_ctx, service, status, unsafe.Pointer(theTun.tunCtx))
+ C.ziti_sdk_c_on_service(ziti_ctx, service, status, unsafe.Pointer(theTun.tunCtx))
+
+ var protocols []string
+ var portRanges []dto.PortRange
+ var addresses []dto.Address
+
+ strClientV1cfg := C.GoString(C.ziti_service_get_raw_config(service, cCfgInterceptV1))
+ if strClientV1cfg != "" {
+ log.Tracef("intercept.v1: %s", strClientV1cfg)
+ var obj clientV1Cfg
+ uerr := json.Unmarshal([]byte(strClientV1cfg), &obj)
+ if uerr != nil {
+ log.Errorf("could not marshall json? %v", uerr)
+ }
+ protocols = obj.Protocols
+ portRanges = obj.PortRanges
+ a := make([]dto.Address, len(obj.Addresses))
+ for idx, add := range obj.Addresses {
+ a[idx] = toAddy(add)
+ }
+
+ addresses = append(a)
+ } else {
+ strZitiTunnelerClientV1 := C.GoString(C.ziti_service_get_raw_config(service, cCfgZitiTunnelerClientV1))
+ log.Tracef("ziti-tunneler-client.v1: %s", strZitiTunnelerClientV1)
+ var obj v1ClientCfg
+ uerr := json.Unmarshal([]byte(strZitiTunnelerClientV1), &obj)
+ if uerr != nil {
+ log.Errorf("could not marshall json? %v", uerr)
+ }
+ protocols = []string{"UDP", "TCP"}
+ portRanges = []dto.PortRange{{Low: obj.Port, High: obj.Port}}
+ addresses = []dto.Address{toAddy(obj.Hostname)}
+ }
- protocols := getTunneledServiceProtocols(ts)
- addresses := getTunneledServiceAddresses(ts)
- portRanges := getTunneledServicePortRanges(ts)
log.Infof("service update: %s, id: %s, portocols:%s, addresses:%v, portRanges: %v", name, svcId, protocols, addresses, portRanges)
+ var svc *dto.Service
+
if status == C.ZITI_SERVICE_UNAVAILABLE {
- serviceUnavailable(zid, svcId, name)
+ log.Debugf("serivce has become unavailable: %s [%s]", name, svcId)
+ f, ok := zid.Services.Load(svcId)
+ if ok {
+ svc = &dto.Service{
+ Name: name,
+ Id: svcId,
+ Addresses: addresses,
+ }
+ found := f.(*ZService)
+ if found != nil {
+ found.Service = nil
+ }
+ zid.Services.Delete(svcId)
+ return svc
+ } else {
+ log.Warnf("could not remove service? service not found with id: %s, name: %s in context %d", svcId, name, &zid)
+ }
} else if status == C.ZITI_OK {
pcIds := make(map[string]bool)
var postureChecks []dto.PostureCheck
@@ -315,7 +373,7 @@ func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, z
}
}
- svc := &dto.Service{
+ svc = &dto.Service{
Name: name,
Id: svcId,
Protocols: protocols,
@@ -325,46 +383,47 @@ func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, z
PostureChecks: postureChecks,
IsAccessable: hasAccess,
}
-
added := ZService{
Name: name,
Id: svcId,
Service: svc,
Czctx: ziti_ctx,
}
-
- se := dto.ServiceEvent{
- ActionEvent: dto.SERVICE_ADDED,
- Fingerprint: zid.Fingerprint,
- Service: svc,
- }
-
zid.Services.Store(svcId, &added)
- go func() {ServiceChanges <- se}() //do this in a go routine just in case it gets blocked so the uv loop doesn't block
}
- return addresses
+
+ return svc
}
-func serviceUnavailable(ctx *ZIdentity, svcId string, name string) {
- log.Debugf("serivce has become unavailalbe: %s [%s]", name, svcId)
- f, ok := ctx.Services.Load(svcId)
- if ok {
- found := f.(*ZService)
- found.Service = nil
- ctx.Services.Delete(svcId)
- se := dto.ServiceEvent{
- ActionEvent: dto.SERVICE_REMOVED,
- Fingerprint: ctx.Fingerprint,
- Service: &dto.Service{
- Name: name,
- Id: svcId,
- },
- }
- ServiceChanges <- se
- log.Debugf("dispatched serivce has become unavailalbe to ui: %s [%s]", name, svcId)
- } else {
- log.Warnf("could not remove service? service not found with id: %s, name: %s in context %d", svcId, name, &ctx)
+func toAddy(hostOrIpOrCidr string) dto.Address {
+ addy := dto.Address{
+ IsHost: false,
+ HostName: "",
+ IP: "",
+ Prefix: 0,
}
+
+ log.Debugf("parsing %s to address", hostOrIpOrCidr)
+ ip, ipnet, err := net.ParseCIDR(hostOrIpOrCidr)
+ if err != nil {
+ //must not be an CIDR... try IP parse
+ ip = net.ParseIP(hostOrIpOrCidr)
+ if ip == nil {
+ log.Debugf("%s does not appear to be an ip/cidr combination. considering it a hostname", hostOrIpOrCidr)
+ addy.HostName = hostOrIpOrCidr
+ addy.IsHost = true
+ } else {
+ log.Debugf("%s determined to be ip", hostOrIpOrCidr)
+ addy.IP = ip.String()
+ }
+ } else {
+ log.Debugf("%s appears to be a proper CIDR", hostOrIpOrCidr)
+ ones, _ := ipnet.Mask.Size()
+ addy.IP = ip.String()
+ addy.Prefix = ones
+ }
+ log.Tracef("parsed address: %v from %s", addy, hostOrIpOrCidr)
+ return addy
}
//export eventCB
@@ -402,6 +461,9 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
case C.ZitiServiceEvent:
hostnamesToAdd := make(map[string]bool)
hostnamesToRemove := make(map[string]bool)
+ servicesToRemove := make([]*dto.Service, 0)
+ servicesToAdd := make([]*dto.Service, 0)
+
srvEvent := C.ziti_event_service_event(event)
for i := 0; true; i++ {
@@ -409,11 +471,16 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
if unsafe.Pointer(removed) == C.NULL {
break
}
- addys := serviceCB(ztx, removed, C.ZITI_SERVICE_UNAVAILABLE, zid)
- for _, toRemove := range addys {
- if toRemove.IsHost {
- hostnamesToRemove[toRemove.HostName] = true
+
+ svcToRemove := serviceCB(ztx, removed, C.ZITI_SERVICE_UNAVAILABLE, zid)
+ if svcToRemove != nil {
+ remAddys := svcToRemove.Addresses
+ for _, toRemove := range remAddys {
+ if toRemove.IsHost && hostnameRemoved(toRemove.HostName) == 0 {
+ hostnamesToRemove[toRemove.HostName] = true
+ }
}
+ servicesToRemove = append(servicesToRemove, svcToRemove)
}
}
for i := 0; true; i++ {
@@ -421,19 +488,29 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
if unsafe.Pointer(changed) == C.NULL {
break
}
+
log.Info("service changed remove the service then add it back immediately", C.GoString(changed.name))
- addys := serviceCB(ztx, changed, C.ZITI_SERVICE_UNAVAILABLE, zid)
- for _, toRemove := range addys {
- if toRemove.IsHost {
- hostnamesToRemove[toRemove.HostName] = true
+ svcToRemove := serviceCB(ztx, changed, C.ZITI_SERVICE_UNAVAILABLE, zid)
+ if svcToRemove != nil {
+
+ remAddys := svcToRemove.Addresses
+ for _, toRemove := range remAddys {
+ if toRemove.IsHost && hostnameRemoved(toRemove.HostName) == 0 {
+ hostnamesToRemove[toRemove.HostName] = true
+ }
}
+ servicesToRemove = append(servicesToRemove, svcToRemove)
}
- addys = serviceCB(ztx, changed, C.ZITI_OK, zid)
- for _, toAdd := range addys {
- if toAdd.IsHost {
- hostnamesToAdd[toAdd.HostName] = true
+ svcToAdd := serviceCB(ztx, changed, C.ZITI_OK, zid)
+ if svcToAdd != nil {
+ addAddys := svcToAdd.Addresses
+ for _, toAdd := range addAddys {
+ if toAdd.IsHost && hostnameAdded(toAdd.HostName) == 1 {
+ hostnamesToAdd[toAdd.HostName] = true
+ }
}
+ servicesToAdd = append(servicesToAdd, svcToAdd)
}
}
for i := 0; true; i++ {
@@ -441,40 +518,37 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
if unsafe.Pointer(added) == C.NULL {
break
}
- addys := serviceCB(ztx, added, C.ZITI_OK, zid)
- for _, toAdd := range addys {
- if toAdd.IsHost {
- hostnamesToAdd[toAdd.HostName] = true
+ svcToAdd := serviceCB(ztx, added, C.ZITI_OK, zid)
+ if svcToAdd != nil {
+ addAddys := svcToAdd.Addresses
+ for _, toAdd := range addAddys {
+ if toAdd.IsHost && hostnameAdded(toAdd.HostName) == 1 {
+ hostnamesToAdd[toAdd.HostName] = true
+ }
}
+ servicesToAdd = append(servicesToAdd, svcToAdd)
}
}
- if len(hostnamesToAdd) > 0 {
- windns.AddNrptRules(hostnamesToAdd, dnsip.String())
- log.Infof("mapped the following hostnames: %v", hostnamesToAdd)
+ svcChange := BulkServiceChange{
+ Fingerprint: zid.Fingerprint,
+ HostnamesToAdd: hostnamesToAdd,
+ HostnamesToRemove: hostnamesToRemove,
+ ServicesToAdd: servicesToAdd,
+ ServicesToRemove: servicesToRemove,
}
- if len(hostnamesToRemove) > 0 {
- windns.RemoveNrptRules(hostnamesToRemove)
- log.Infof("unmapped the following hostnames: %v", hostnamesToRemove)
+ if len(BulkServiceChanges) == cap(BulkServiceChanges) {
+ log.Warn("Service changes are not being processed fast enough. This client is out of date from the controller! This is unexpected. If you see this warning please report")
+ } else {
+ BulkServiceChanges <- svcChange
}
-
- var m = dto.IdentityEvent{
- ActionEvent: dto.IdentityUpdateComplete,
- Id: dto.Identity{
- FingerPrint: zid.Fingerprint,
- },
- }
-
- goapi.BroadcastEvent(m)
-
default:
log.Infof("event %d not handled", event._type)
}
}
func zitiContextEvent(ztx C.ziti_context, status C.int, zid *ZIdentity) {
-
zid.status = int(status)
zid.statusErr = zitiError(status)
zid.czctx = ztx
@@ -605,81 +679,35 @@ func ziti_dump_go_to_log_cb(stringsBuilder unsafe.Pointer, charData *C.char) {
sb := (*strings.Builder)(stringsBuilder)
sb.WriteString(C.GoString(charData))
}
-func ZitiDumpOnShutdown(zid *ZIdentity, sb *strings.Builder) {
- C.ziti_dump_to_log(unsafe.Pointer(zid.czctx), unsafe.Pointer(sb))
-}
-
-func getTunneledServiceProtocols(ts *C.tunneled_service_t) []string {
- var protocols []string
- next := C.stailq_first_protocol(ts)
- if unsafe.Pointer(next) != C.NULL {
- protocols = append(protocols, C.GoString(next.protocol))
- for {
- next = C.stailq_next_protocol(next)
- if unsafe.Pointer(next) != C.NULL {
- protocols = append(protocols, C.GoString(next.protocol))
- } else {
- break
- }
- }
- }
- return protocols
-}
-
-func getTunneledServicePortRanges(ts *C.tunneled_service_t) []dto.PortRange {
- var values []dto.PortRange
- next := C.stailq_first_port_range(ts)
- if unsafe.Pointer(next) != C.NULL {
- p := dto.PortRange{
- High: int(next.high),
- Low: int(next.low),
- }
- values = append(values, p)
- for {
- next = C.stailq_next_port_range(next)
- if unsafe.Pointer(next) != C.NULL {
- p := dto.PortRange{
- High: int(next.high),
- Low: int(next.low),
- }
- values = append(values, p)
- } else {
- break
- }
- }
- }
- return values
-}
-
-func getTunneledServiceAddresses(ts *C.tunneled_service_t) []dto.Address {
- var values []dto.Address
- next := C.stailq_first_address(ts)
- if unsafe.Pointer(next) != C.NULL {
- p := dto.Address{
- IsHost: bool(next.is_hostname),
- HostName: C.GoString(&next.str[0]),
- IP: C.GoString(C.ipaddr_ntoa(&next.ip)),
- Prefix: int(next.prefix_len),
- }
- values = append(values, p)
- for {
- next = C.stailq_next_address(next)
- if unsafe.Pointer(next) != C.NULL {
- p := dto.Address{
- IsHost: bool(next.is_hostname),
- HostName: C.GoString(&next.str[0]),
- IP: C.GoString(C.ipaddr_ntoa(&next.ip)),
- Prefix: int(next.prefix_len),
- }
- values = append(values, p)
- } else {
- break
- }
- }
- }
- return values
+func ZitiDumpOnShutdown(zid *ZIdentity) {
+ sb := strings.Builder{}
+ C.ziti_dump_to_log(unsafe.Pointer(zid.czctx), unsafe.Pointer(&sb))
+ log.Infof("working around the c sdk's limitation of embedding newlines on calling ziti_shutdown\n %s", sb.String())
}
func InitTunnelerDns(ipBase uint32, mask int) {
C.ziti_tunneler_init_dns(C.uint32_t(ipBase), C.int(mask))
}
+
+var addressCount = make(map[string]int)
+
+func hostnameAdded(host string) int {
+ count := 1
+ if cur, ok := addressCount[host]; ok {
+ count = cur + 1
+ }
+ addressCount[host] = count
+ log.Debugf("hostname added: %s. count now: %d", host, count)
+ return count
+}
+func hostnameRemoved(host string) int {
+ count := 0
+ if cur, ok := addressCount[host]; ok {
+ if cur > 0 {
+ count = cur - 1
+ }
+ }
+ addressCount[host] = count
+ log.Debugf("hostname removed %s. count now: %d", host, count)
+ return count
+}
diff --git a/service/debug.bat b/service/debug.bat
index 0775e9bd..bb99fe88 100644
--- a/service/debug.bat
+++ b/service/debug.bat
@@ -1 +1 @@
-cls & "c:\Program Files\JetBrains\GoLand 2020.1.1\plugins\go\lib\dlv\windows\dlv.exe" --listen=localhost:50000 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec c:\git\github\openziti\desktop-edge-win\service\ziti-tunnel.exe debug
+cls & "c:\Program Files\JetBrains\GoLand 2020.1.1\plugins\go\lib\dlv\windows\dlv.exe" --listen=localhost:50000 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec ziti-tunnel.exe debug
diff --git a/service/windns/windns.go b/service/windns/windns.go
index 54dd0cbf..ae2897c0 100644
--- a/service/windns/windns.go
+++ b/service/windns/windns.go
@@ -27,7 +27,12 @@ import (
"strings"
)
+const (
+ MAX_POWERSHELL_SCRIPT_LEN = 7500 //represents how long the powershell script can be. as of apr 2021 the limit was 8k (8192). leaves a little room for the rest of the script
+)
+
var log = logging.Logger()
+var exeName = "ziti-tunnel"
func GetConnectionSpecificDomains() []string {
script := `Get-DnsClient | Select-Object ConnectionSpecificSuffix -Unique | ForEach-Object { $_.ConnectionSpecificSuffix }; (Get-DnsClientGlobalSetting).SuffixSearchList`
@@ -103,8 +108,8 @@ func FlushDNS() {
}
func RemoveAllNrptRules() {
- script := fmt.Sprintf(`Get-DnsClientNrptRule | Where { $_.Comment.StartsWith("Added by ziti-tunnel") } | Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force`)
- log.Debugf("removing all nrpt rules with: %s", script)
+ script := fmt.Sprintf(`Get-DnsClientNrptRule | Where { $_.Comment.StartsWith("Added by %s") } | Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force`, exeName)
+ log.Tracef("removing all nrpt rules with: %s", script)
cmd := exec.Command("powershell", "-Command", script)
cmd.Stderr = os.Stdout
@@ -116,24 +121,27 @@ func RemoveAllNrptRules() {
}
}
+var namespaceTemplate = `%s@{n="%s";}`
+var namespaceTemplatePadding = len(namespaceTemplate)
+
func AddNrptRules(domainsToMap map[string]bool, dnsServer string) {
if len(domainsToMap) == 0 {
log.Debug("no domains to map specified to AddNrptRules. exiting early")
return
}
- blockSize := 50
- if len(domainsToMap) > blockSize {
- log.Debugf("domainsToMap is too long [%d] and may fail on some systems. splitting the requested entries into blocks of %d", len(domainsToMap), blockSize)
- }
+ maxBucketSize := 500
currentSize := 0
- hostnames := make([]string, blockSize)
+ hostnames := make([]string, maxBucketSize)
+ ruleSize := 0
for hostname := range domainsToMap {
- if currentSize >= blockSize {
+ ruleSize = ruleSize + len(hostname) + namespaceTemplatePadding
+ if ruleSize > MAX_POWERSHELL_SCRIPT_LEN || currentSize >= maxBucketSize {
log.Debugf("sending chunk of domains to be added to NRPT")
- chunkedAddNrptRules(hostnames, dnsServer)
- hostnames = make([]string, blockSize)
+ chunkedAddNrptRules(hostnames[:currentSize], dnsServer)
+ hostnames = make([]string, maxBucketSize)
currentSize = 0
+ ruleSize = len(hostname) + namespaceTemplatePadding
}
hostnames[currentSize] = hostname
currentSize++
@@ -146,21 +154,23 @@ func AddNrptRules(domainsToMap map[string]bool, dnsServer string) {
func chunkedAddNrptRules(domainsToAdd []string, dnsServer string) {
sb := strings.Builder{}
- sb.WriteString(`$Rules = @(
+ sb.WriteString(`$Namespaces = @(
`)
for _, hostname := range domainsToAdd {
- sb.WriteString(fmt.Sprintf(`@{ Namespace ="%s"; NameServers = @("%s"); Comment = "Added by ziti-tunnel"; DisplayName = "ziti-tunnel:%s"; }%s`, hostname, dnsServer, hostname, "\n"))
+ sb.WriteString(fmt.Sprintf(namespaceTemplate, "\n", hostname))
}
sb.WriteString(fmt.Sprintf(`)
-ForEach ($Rule in $Rules) {
- Add-DnsClientNrptRule @Rule
-}`))
+ForEach ($Namespace in $Namespaces) {
+ $ns=$Namespace["n"]
+ $Rule = @{Namespace="${ns}"; NameServers=@("%s"); Comment="Added by %s"; DisplayName="%s:${ns}"; }
+ Add-DnsClientNrptRule @Rule
+}`, dnsServer, exeName, exeName))
script := sb.String()
- log.Debugf("Executing NRPT script containing %d domains:\n%s", len(domainsToAdd), script)
+ log.Tracef("Executing ADD NRPT script containing %d domains. total script size: %d\n%s", len(domainsToAdd), len(script), script)
cmd := exec.Command("powershell", "-Command", script)
cmd.Stderr = os.Stdout
@@ -172,27 +182,52 @@ ForEach ($Rule in $Rules) {
}
}
-func RemoveNrptRules(domainsToMap map[string]bool) {
- if len(domainsToMap) == 0 {
+func RemoveNrptRules(domainsToRemove map[string]bool) {
+ if len(domainsToRemove) == 0 {
log.Debug("no domains to map specified to RemoveNrptRules. exiting early")
return
}
- sb := strings.Builder{}
- sb.WriteString(`$toRemove = @(
-`)
+ maxBucketSize := 500
+ currentSize := 0
+ hostnames := make([]string, maxBucketSize)
+ ruleSize := 0
+ for hostname := range domainsToRemove {
+ ruleSize = ruleSize + len(hostname) + namespaceTemplatePadding
+ if ruleSize > MAX_POWERSHELL_SCRIPT_LEN || currentSize >= maxBucketSize {
+ log.Debugf("sending chunk of domains to be added to NRPT")
+ chunkedRemoveNrptRules(hostnames[:currentSize])
+ hostnames = make([]string, maxBucketSize)
+ currentSize = 0
+ ruleSize = len(hostname) + namespaceTemplatePadding
+ }
+ hostnames[currentSize] = hostname
+ currentSize++
+ }
- for hostname := range domainsToMap {
- sb.WriteString(fmt.Sprintf(`"%s"%s`, hostname, "\n"))
+ if currentSize > 0 {
+ //means there's a chunk still to add....
+ chunkedRemoveNrptRules(hostnames[:currentSize])
+ }
+}
+
+func chunkedRemoveNrptRules(domainsToRemove []string) {
+ sb := strings.Builder{}
+ sb.WriteString(`$toRemove = @(`)
+
+ for _, hostname := range domainsToRemove {
+ sb.WriteString(fmt.Sprintf(namespaceTemplate, "\n", hostname))
}
sb.WriteString(fmt.Sprintf(`)
-Get-DnsClientNrptRule | Where { $toRemove -contains $_.DisplayName } | Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force
+ForEach ($ns in $toRemove){
+ Get-DnsClientNrptRule | where Namespace -eq $ns["n"] | Remove-DnsClientNrptRule -Force -ErrorAction SilentlyContinue
+}
`))
script := sb.String()
- log.Debugf("Executing NRPT script:\n%s", script)
+ log.Tracef("Executing REMOVE NRPT script containing %d domains. total script size: %d\n%s", len(domainsToRemove), len(script), script)
cmd := exec.Command("powershell", "-Command", script)
cmd.Stderr = os.Stdout
diff --git a/service/ziti-tunnel/cli/ipcClient.go b/service/ziti-tunnel/cli/ipcClient.go
index c2316fe3..50a87b94 100644
--- a/service/ziti-tunnel/cli/ipcClient.go
+++ b/service/ziti-tunnel/cli/ipcClient.go
@@ -18,9 +18,9 @@ package cli
*/
import (
- "fmt"
"bufio"
"encoding/json"
+ "fmt"
"io"
"net"
"strings"
diff --git a/service/ziti-tunnel/dto/dtos.go b/service/ziti-tunnel/dto/dtos.go
index d63105f6..c8930d43 100644
--- a/service/ziti-tunnel/dto/dtos.go
+++ b/service/ziti-tunnel/dto/dtos.go
@@ -119,6 +119,7 @@ type TunnelStatus struct {
TunIpv4 string
TunIpv4Mask int
Status string
+ AddDns bool
}
type ServiceVersion struct {
@@ -152,10 +153,11 @@ type MetricsEvent struct {
Identities []*Identity
}
-type ServiceEvent struct {
+type BulkServiceEvent struct {
ActionEvent
- Fingerprint string
- Service *Service
+ Fingerprint string
+ AddedServices []*Service
+ RemovedServices []*Service
}
type IdentityEvent struct {
diff --git a/service/ziti-tunnel/dto/events.go b/service/ziti-tunnel/dto/events.go
index c216ced3..e2e43379 100644
--- a/service/ziti-tunnel/dto/events.go
+++ b/service/ziti-tunnel/dto/events.go
@@ -18,17 +18,19 @@ package dto
const (
ADDED = "added"
+ BULK = "bulk"
REMOVED = "removed"
ERROR = "error"
UPDATED = "updated"
CHANGED = "changed"
NORMAL = "Normal"
- SERVICE_OP = "service"
- IDENTITY_OP = "identity"
- LOGLEVEL_OP = "logLevel"
- FEEDBACK_OP = "CaptureLogs"
- MFA_OP = "mfa"
+ SERVICE_OP = "service"
+ BULK_SERVICE_OP = "bulkservice"
+ IDENTITY_OP = "identity"
+ LOGLEVEL_OP = "logLevel"
+ FEEDBACK_OP = "CaptureLogs"
+ MFA_OP = "mfa"
MFAEnrollmentChallengAtion = "enrollment_challenge"
MFAEnrollmentVerificationAction = "enrollment_verification"
@@ -45,6 +47,10 @@ var SERVICE_REMOVED = ActionEvent{
StatusEvent: StatusEvent{Op: SERVICE_OP},
Action: REMOVED,
}
+var SERVICE_BULK = ActionEvent{
+ StatusEvent: StatusEvent{Op: BULK_SERVICE_OP},
+ Action: BULK,
+}
var IDENTITY_ADDED = ActionEvent{
StatusEvent: StatusEvent{Op: IDENTITY_OP},
diff --git a/service/ziti-tunnel/service/debug.go b/service/ziti-tunnel/service/debug.go
index 47f87435..2050ff80 100644
--- a/service/ziti-tunnel/service/debug.go
+++ b/service/ziti-tunnel/service/debug.go
@@ -25,11 +25,11 @@ import (
func dbg() {
r := rts.ToStatus(true)
- events.broadcast <- dto.TunnelStatusEvent{
+ rts.BroadcastEvent(dto.TunnelStatusEvent{
StatusEvent: dto.StatusEvent{Op: "status"},
Status: r,
ApiVersion: API_VERSION,
- }
+ })
svcs := make([]*dto.Service, 2)
svcs[0] = &dto.Service{
@@ -39,7 +39,7 @@ func dbg() {
Name: "Second Fake Service",
}
- events.broadcast <- dto.IdentityEvent{
+ rts.BroadcastEvent(dto.IdentityEvent{
ActionEvent: dto.IDENTITY_ADDED,
Id: dto.Identity{
Name: "NewIdentity",
@@ -52,25 +52,9 @@ func dbg() {
Services: svcs,
Metrics: nil,
},
- }
+ })
- events.broadcast <- dto.ServiceEvent{
- ActionEvent: dto.SERVICE_ADDED,
- Service: &dto.Service{
- Name: "New Service",
- },
- Fingerprint: "new_id_fingerprint",
- }
-
- events.broadcast <- dto.ServiceEvent{
- ActionEvent: dto.SERVICE_REMOVED,
- Service: &dto.Service{
- Name: "New Service",
- },
- Fingerprint: "new_id_fingerprint",
- }
-
- events.broadcast <- dto.IdentityEvent{
+ rts.BroadcastEvent(dto.IdentityEvent{
ActionEvent: dto.IDENTITY_REMOVED,
Id: dto.Identity{
Name: "",
@@ -81,5 +65,5 @@ func dbg() {
Services: nil,
Metrics: nil,
},
- }
+ })
}
diff --git a/service/ziti-tunnel/service/ipc.go b/service/ziti-tunnel/service/ipc.go
index 04aca3fd..4bd5cf49 100644
--- a/service/ziti-tunnel/service/ipc.go
+++ b/service/ziti-tunnel/service/ipc.go
@@ -119,9 +119,7 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
log.Debug("shutting down. start a ZitiDump")
for _, id := range rts.ids {
if id.CId != nil {
- sb := strings.Builder{}
- cziti.ZitiDumpOnShutdown(id.CId, &sb)
- log.Infof("working around the c sdk's limitation of embedding newlines on calling ziti_shutdown\n %s", sb.String())
+ cziti.ZitiDumpOnShutdown(id.CId)
}
}
log.Debug("shutting down. ZitiDump complete")
@@ -129,9 +127,9 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
requestShutdown("service shutdown")
// signal to any connected consumers that the service is shutting down normally
- events.broadcast <- dto.StatusEvent{
+ rts.BroadcastEvent(dto.StatusEvent{
Op: "shutdown",
- }
+ })
// wait 1 second for the shutdown to send to clients
shutdownDelay := make(chan bool)
@@ -282,7 +280,7 @@ func initialize(cLogLevel int) error {
dnsIpAsUint32 := binary.BigEndian.Uint32(ipnet.IP)
cziti.InitTunnelerDns(dnsIpAsUint32, len(ipnet.Mask))
- assignedIp, t, err := rts.CreateTun(rts.state.TunIpv4, rts.state.TunIpv4Mask)
+ assignedIp, t, err := rts.CreateTun(rts.state.TunIpv4, rts.state.TunIpv4Mask, rts.state.AddDns)
if err != nil {
return err
}
@@ -681,8 +679,9 @@ func serveEvents(conn net.Conn) {
log.Debugf("accepting a new client for serveEvents. total connection count: %d", eventsConnections)
consumer := make(chan interface{}, 8)
- events.register(randomInt, consumer)
- defer events.unregister(randomInt)
+ id := fmt.Sprintf("serveEvents:%d", randomInt)
+ events.register(id, consumer)
+ defer events.unregister(id)
w := bufio.NewWriter(conn)
o := json.NewEncoder(w)
@@ -704,12 +703,18 @@ loop:
for {
select {
case msg := <-consumer:
- err := o.Encode(msg)
- if err != nil {
- log.Debugf("exiting from serveEvents - %v", err)
+ log.Tracef("sending event to id: %s [%v]", id, msg)
+ eerr := o.Encode(msg)
+ if eerr != nil {
+ log.Warnf("exiting from serveEvents due to error: %v", eerr)
break loop
}
- _ = w.Flush()
+ ferr := w.Flush()
+ if ferr != nil {
+ log.Warnf("flush error: %v", ferr)
+ return
+ }
+ log.Tracef("sent event to id: %s [%v]", id, msg)
case <-interrupt:
break loop
}
@@ -717,6 +722,10 @@ loop:
log.Info("a connected event client has disconnected")
}
+func writerFlush(writer bufio.Writer) {
+ writer.Flush()
+}
+
func reportStatus(out *json.Encoder) {
s := rts.ToStatus(true)
respond(out, dto.ZitiTunnelStatus{
@@ -901,10 +910,10 @@ func connectIdentity(id *Id) {
return true
})
- events.broadcast <- dto.IdentityEvent{
+ rts.BroadcastEvent(dto.IdentityEvent{
ActionEvent: dto.IDENTITY_ADDED,
Id: id.Identity,
- }
+ })
log.Infof("connecting identity completed: %s[%s] %t/%t", id.Name, id.FingerPrint, id.MfaEnabled, id.MfaNeeded)
}
}
@@ -1003,15 +1012,50 @@ func acceptServices() {
select {
case <-shutdown:
return
- case serviceChange := <-cziti.ServiceChanges:
- log.Debugf("processing service change event. id:%s name:%s", serviceChange.Service.Id, serviceChange.Service.Name)
- change := dto.ServiceEvent(serviceChange)
- events.broadcast <- change
- log.Debugf("dispatched %s service change event", serviceChange.Op)
+ case bulkServiceChange := <-cziti.BulkServiceChanges:
+ log.Debugf("processing a bulk service change event. Hostnames to add/remove:[%d/%d] service notifications added/removed: [%d/%d]",
+ len(bulkServiceChange.HostnamesToAdd),
+ len(bulkServiceChange.HostnamesToRemove),
+ len(bulkServiceChange.ServicesToAdd),
+ len(bulkServiceChange.ServicesToRemove))
+ handleBulkServiceChange(bulkServiceChange)
}
}
}
+func handleBulkServiceChange(sc cziti.BulkServiceChange) {
+ if len(sc.HostnamesToRemove) > 0 {
+ log.Debug("removing rules from NRPT")
+ windns.RemoveNrptRules(sc.HostnamesToRemove)
+ log.Info("removed NRPT rules for: %v", sc.HostnamesToRemove)
+ } else {
+ log.Debug("bulk service change had no hostnames to remove")
+ }
+
+ if len(sc.HostnamesToAdd) > 0 {
+ log.Debug("adding rules to NRPT")
+ windns.AddNrptRules(sc.HostnamesToAdd, rts.state.TunIpv4)
+ log.Infof("mapped the following hostnames: %v", sc.HostnamesToAdd)
+ }
+
+ be := dto.BulkServiceEvent{
+ ActionEvent: dto.SERVICE_BULK,
+ Fingerprint: sc.Fingerprint,
+ AddedServices: sc.ServicesToAdd,
+ RemovedServices: sc.ServicesToRemove,
+ }
+
+ rts.BroadcastEvent(be)
+
+ var m = dto.IdentityEvent{
+ ActionEvent: dto.IdentityUpdateComplete,
+ Id: dto.Identity{
+ FingerPrint: sc.Fingerprint,
+ },
+ }
+ rts.BroadcastEvent(m)
+}
+
func handleEvents(isInitialized chan struct{}) {
events.run()
d := 5 * time.Second
@@ -1027,10 +1071,10 @@ func handleEvents(isInitialized chan struct{}) {
case <-every5s.C:
s := rts.ToMetrics()
- events.broadcast <- dto.MetricsEvent{
+ rts.BroadcastEvent(dto.MetricsEvent{
StatusEvent: dto.StatusEvent{Op: "metrics"},
Identities: s.Identities,
- }
+ })
}
}
}
@@ -1098,10 +1142,10 @@ func authMfa(out *json.Encoder, fingerprint string, code string) {
// when the log level is updated through command line, the message is broadcasted to UI and update service as well
func sendLogLevelAndNotify(enc *json.Encoder, loglevel string) {
- events.broadcast <- dto.LogLevelEvent{
+ rts.BroadcastEvent(dto.LogLevelEvent{
ActionEvent: dto.LOGLEVEL_CHANGED,
LogLevel: loglevel,
- }
+ })
message := fmt.Sprintf("Loglevel %s is sent to the events channel", loglevel)
log.Info(message)
resp := dto.Response{Message: "success", Code: SUCCESS, Error: "", Payload: message}
@@ -1112,10 +1156,10 @@ func sendLogLevelAndNotify(enc *json.Encoder, loglevel string) {
func sendIdentityAndNotifyUI(enc *json.Encoder, fingerprint string) {
for _, id := range rts.ids {
if id.FingerPrint == fingerprint {
- events.broadcast <- dto.IdentityEvent{
+ rts.BroadcastEvent(dto.IdentityEvent{
ActionEvent: dto.IDENTITY_ADDED,
Id: id.Identity,
- }
+ })
message := fmt.Sprintf("Identity %s - %s updated message is sent to the events channel", id.Identity.Name, id.Identity.FingerPrint)
log.Info(message)
resp := dto.Response{Message: "success", Code: SUCCESS, Error: "", Payload: message}
diff --git a/service/ziti-tunnel/service/state.go b/service/ziti-tunnel/service/state.go
index 26933a70..cb5b06a3 100644
--- a/service/ziti-tunnel/service/state.go
+++ b/service/ziti-tunnel/service/state.go
@@ -21,6 +21,7 @@ import (
"bufio"
"encoding/json"
"fmt"
+ "golang.org/x/sys/windows"
"io"
"io/ioutil"
"net"
@@ -121,6 +122,7 @@ func (t *RuntimeState) ToStatus(onlyInitialized bool) dto.TunnelStatus {
ServiceVersion: Version,
TunIpv4: t.state.TunIpv4,
TunIpv4Mask: t.state.TunIpv4Mask,
+ AddDns: t.state.AddDns,
}
i := 0
@@ -162,7 +164,7 @@ func (t *RuntimeState) ToMetrics() dto.TunnelStatus {
return clean
}
-func (t *RuntimeState) CreateTun(ipv4 string, ipv4mask int) (net.IP, *tun.Device, error) {
+func (t *RuntimeState) CreateTun(ipv4 string, ipv4mask int, applyDns bool) (net.IP, *tun.Device, error) {
log.Infof("creating TUN device: %s", TunName)
tunDevice, err := tun.CreateTUN(TunName, 64*1024-1)
if err == nil {
@@ -219,6 +221,11 @@ func (t *RuntimeState) CreateTun(ipv4 string, ipv4mask int) (net.IP, *tun.Device
}
log.Info("routing applied")
+ if applyDns {
+ //for windows 10+, could 'domains' be able to replace NRPT? dunno - didn't test it
+ luid.SetDNS(windows.AF_INET, []net.IP{ip}, nil)
+ }
+
return ip, t.tun, nil
}
@@ -262,10 +269,10 @@ func (t *RuntimeState) LoadIdentity(id *Id, refreshInterval int) {
id.MfaEnabled = id.CId.MfaEnabled
id.MfaNeeded = id.CId.MfaNeeded
- events.broadcast <- dto.IdentityEvent{
+ rts.BroadcastEvent(dto.IdentityEvent{
ActionEvent: dto.IDENTITY_ADDED,
Id: id.Identity,
- }
+ })
log.Infof("connecting identity completed: %s[%s] %t/%t", id.Name, id.FingerPrint, id.MfaEnabled, id.MfaNeeded)
}
@@ -477,6 +484,9 @@ func (t *RuntimeState) ReleaseIP() {
}
func (t *RuntimeState) BroadcastEvent(event interface{}) {
+ if len(events.broadcast) == cap(events.broadcast) {
+ log.Warn("event channel is full and is about to block!")
+ }
events.broadcast <- event
}
diff --git a/service/ziti-tunnel/service/topic.go b/service/ziti-tunnel/service/topic.go
index c6d95897..beb5dbd5 100644
--- a/service/ziti-tunnel/service/topic.go
+++ b/service/ziti-tunnel/service/topic.go
@@ -19,23 +19,23 @@ package service
type topic struct {
broadcast chan interface{}
- channels map[int]chan interface{}
+ channels map[string]chan interface{}
done chan bool
}
func newTopic(cap int16) topic {
return topic{
broadcast: make(chan interface{}, cap),
- channels: make(map[int]chan interface{}, cap),
+ channels: make(map[string]chan interface{}, cap),
done: make(chan bool, cap),
}
}
-func (t *topic) register(id int, c chan interface{}) {
+func (t *topic) register(id string, c chan interface{}) {
t.channels[id] = c
}
-func (t *topic) unregister(id int) {
+func (t *topic) unregister(id string) {
delete(t.channels, id)
}
@@ -48,7 +48,10 @@ func (t *topic) run() {
for {
select {
case msg := <-t.broadcast:
- for _, c := range t.channels {
+ for id, c := range t.channels {
+ if len(c) == cap(c) {
+ log.Warnf("channel with id [%s] is about to block!", id)
+ }
c <- msg
}
break
diff --git a/service/ziti-tunnel/version.go b/service/ziti-tunnel/version.go
index f80071c9..3fed4615 100644
--- a/service/ziti-tunnel/version.go
+++ b/service/ziti-tunnel/version.go
@@ -20,9 +20,9 @@
package main
const (
- Version = "1.9.2"
- Revision = "4e9875920983"
- Branch = "main"
+ Version = "1.9.3"
+ Revision = "b6361cdb1b8d"
+ Branch = "release-next"
BuildUser = ""
- BuildDate = "2021-04-08 11:05:00"
+ BuildDate = "2021-04-12 17:20:21"
)
diff --git a/version b/version
index 8fdcf386..77fee73a 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.9.2
+1.9.3