From 8b7ce23a829bddbe9622930995852dc486c30250 Mon Sep 17 00:00:00 2001
From: ChsBuffer <33744752+chsbuffer@users.noreply.github.com>
Date: Tue, 22 Sep 2020 17:57:26 +0800
Subject: [PATCH] Add TAP Adapter Internet Network Sharing Setting(ICS)
---
Netch/Controllers/ICSController.cs | 174 +++++++++++++++
Netch/Controllers/Mode/TUNTAPController.cs | 2 +-
Netch/Forms/SettingForm.Designer.cs | 16 ++
Netch/Forms/SettingForm.cs | 27 ++-
Netch/Models/WinFW/NetworkConnection.cs | 114 ++++++++++
.../WinFW/NetworkConnectionCollection.cs | 201 ++++++++++++++++++
Netch/Netch.csproj | 9 +
7 files changed, 540 insertions(+), 3 deletions(-)
create mode 100644 Netch/Controllers/ICSController.cs
create mode 100644 Netch/Models/WinFW/NetworkConnection.cs
create mode 100644 Netch/Models/WinFW/NetworkConnectionCollection.cs
diff --git a/Netch/Controllers/ICSController.cs b/Netch/Controllers/ICSController.cs
new file mode 100644
index 00000000..16d3aa4a
--- /dev/null
+++ b/Netch/Controllers/ICSController.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Management;
+using Netch.Utils;
+using NETCONLib;
+using WinFW;
+
+namespace Netch.Controllers
+{
+ public class ICSController
+ {
+ public static bool Enabled
+ {
+ get
+ {
+ TUNTAPController.SearchTapAdapter();
+ foreach (NetworkConnection connection in new NetworkConnectionCollection())
+ {
+ if (connection.DeviceName == Global.TUNTAP.Adapter.Description)
+ {
+ return connection.SharingEnabled;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ public static bool Enable()
+ {
+ Utils.Utils.SearchOutboundAdapter();
+ TUNTAPController.SearchTapAdapter();
+
+ if (Global.TUNTAP.Adapter == null || Global.Outbound.Adapter == null)
+ {
+ return false;
+ }
+
+ try
+ {
+ CleanupWMISharingEntries();
+
+ #region Save Outbound IP Config
+
+ var wmi = new ManagementClass("Win32_NetworkAdapterConfiguration");
+ var moc = wmi.GetInstances();
+
+ var dhcpEnabled = true;
+ string[] ipAddress = null;
+ string[] subnetMask = null;
+ string[] gateway = null;
+ ushort[] gatewayMetric = null;
+ string[] dns = null;
+
+ ManagementObject outboundWmi = null;
+ foreach (ManagementObject mo in moc)
+ {
+ if (((string) mo["Caption"]).EndsWith(Global.Outbound.Adapter.Description))
+ {
+ outboundWmi = mo;
+ if (!(dhcpEnabled = (bool) mo["DHCPEnabled"]))
+ {
+ ipAddress = (string[]) mo["IPAddress"];
+ subnetMask = (string[]) mo["IPSubnet"];
+ gateway = (string[]) mo["DefaultIPGateway"];
+ gatewayMetric = (ushort[]) mo["GatewayCostMetric"];
+ dns = (string[]) mo["DNSServerSearchOrder"];
+
+ ipAddress = new[] {ipAddress[0]};
+ subnetMask = new[] {subnetMask[0]};
+ }
+
+ break;
+ }
+ }
+
+ #endregion
+
+ #region Setting ICS
+
+ foreach (NetworkConnection connection in new NetworkConnectionCollection())
+ {
+ if (connection.DeviceName == Global.TUNTAP.Adapter.Description)
+ {
+ if (connection.SharingEnabled)
+ connection.DisableSharing();
+ connection.EnableSharing(tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PUBLIC);
+ }
+ else if (connection.DeviceName == Global.Outbound.Adapter.Description)
+ {
+ if (connection.SharingEnabled)
+ connection.DisableSharing();
+ connection.EnableSharing(tagSHARINGCONNECTIONTYPE.ICSSHARINGTYPE_PRIVATE);
+ }
+ }
+
+ #endregion
+
+ #region Reset Outbound IP Config
+
+ if (dhcpEnabled)
+ {
+ outboundWmi.InvokeMethod("EnableDHCP", null, null);
+ }
+ else
+ {
+ //Set static IP and subnet mask
+ var newIP = outboundWmi.GetMethodParameters("EnableStatic");
+ newIP["IPAddress"] = ipAddress;
+ newIP["SubnetMask"] = subnetMask;
+ outboundWmi.InvokeMethod("EnableStatic", newIP, null);
+ //Set default gateway
+ var newGateway = outboundWmi.GetMethodParameters("SetGateways");
+ newGateway["DefaultIPGateway"] = gateway;
+ newGateway["GatewayCostMetric"] = gatewayMetric;
+ outboundWmi.InvokeMethod("SetGateways", newGateway, null);
+ //Set dns servers
+ var newDNS = outboundWmi.GetMethodParameters("SetDNSServerSearchOrder");
+ newDNS["DNSServerSearchOrder"] = dns;
+ outboundWmi.InvokeMethod("SetDNSServerSearchOrder", newDNS, null);
+ }
+
+ #endregion
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ Disable();
+ }
+ catch
+ {
+ // ignored
+ }
+
+ Logging.Error($"网络连接共享设置失败: {e}");
+
+ return false;
+ }
+ }
+
+ public static void Disable()
+ {
+ foreach (NetworkConnection connection in new NetworkConnectionCollection())
+ {
+ if (connection.SharingEnabled)
+ connection.DisableSharing();
+ }
+
+ CleanupWMISharingEntries();
+ }
+
+ private static void CleanupWMISharingEntries()
+ {
+ var scope = new ManagementScope("root\\Microsoft\\HomeNet");
+ scope.Connect();
+
+ var options = new PutOptions();
+ options.Type = PutType.UpdateOnly;
+
+ var query = new ObjectQuery("SELECT * FROM HNet_ConnectionProperties");
+ var srchr = new ManagementObjectSearcher(scope, query);
+ foreach (ManagementObject entry in srchr.Get())
+ {
+ if ((bool) entry["IsIcsPrivate"])
+ entry["IsIcsPrivate"] = false;
+ if ((bool) entry["IsIcsPublic"])
+ entry["IsIcsPublic"] = false;
+ entry.Put(options);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Netch/Controllers/Mode/TUNTAPController.cs b/Netch/Controllers/Mode/TUNTAPController.cs
index fb423dac..8eb97931 100644
--- a/Netch/Controllers/Mode/TUNTAPController.cs
+++ b/Netch/Controllers/Mode/TUNTAPController.cs
@@ -224,7 +224,7 @@ namespace Netch.Controllers
}
else
{
- pDNSController.Start();
+ var _ = pDNSController.Start();
dns = "127.0.0.1";
}
diff --git a/Netch/Forms/SettingForm.Designer.cs b/Netch/Forms/SettingForm.Designer.cs
index 18bb10bf..bd9ac273 100644
--- a/Netch/Forms/SettingForm.Designer.cs
+++ b/Netch/Forms/SettingForm.Designer.cs
@@ -40,6 +40,7 @@
this.TUNTAPGroupBox = new System.Windows.Forms.GroupBox();
this.UseFakeDNSCheckBox = new System.Windows.Forms.CheckBox();
this.ProxyDNSCheckBox = new System.Windows.Forms.CheckBox();
+ this.ICSCheckBox = new System.Windows.Forms.CheckBox();
this.UseCustomDNSCheckBox = new System.Windows.Forms.CheckBox();
this.TUNTAPDNSLabel = new System.Windows.Forms.Label();
this.TUNTAPDNSTextBox = new System.Windows.Forms.TextBox();
@@ -160,6 +161,7 @@
//
this.TUNTAPGroupBox.Controls.Add(this.UseFakeDNSCheckBox);
this.TUNTAPGroupBox.Controls.Add(this.ProxyDNSCheckBox);
+ this.TUNTAPGroupBox.Controls.Add(this.ICSCheckBox);
this.TUNTAPGroupBox.Controls.Add(this.UseCustomDNSCheckBox);
this.TUNTAPGroupBox.Controls.Add(this.TUNTAPDNSLabel);
this.TUNTAPGroupBox.Controls.Add(this.TUNTAPDNSTextBox);
@@ -197,6 +199,18 @@
this.ProxyDNSCheckBox.Text = "Proxy DNS in Mode 2";
this.ProxyDNSCheckBox.UseVisualStyleBackColor = true;
//
+ // ICSCheckBox
+ //
+ this.ICSCheckBox.AutoSize = true;
+ this.ICSCheckBox.Location = new System.Drawing.Point(261, 160);
+ this.ICSCheckBox.Name = "ICSCheckBox";
+ this.ICSCheckBox.Size = new System.Drawing.Size(46, 21);
+ this.ICSCheckBox.TabIndex = 5;
+ this.ICSCheckBox.Text = "ICS";
+ this.ICSCheckBox.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.ICSCheckBox.UseVisualStyleBackColor = true;
+ this.ICSCheckBox.CheckedChanged += new System.EventHandler(this.ICSCheckBox_CheckedChanged);
+ //
// UseCustomDNSCheckBox
//
this.UseCustomDNSCheckBox.AutoSize = true;
@@ -559,6 +573,8 @@
this.ResumeLayout(false);
}
+ private System.Windows.Forms.CheckBox ICSCheckBox;
+
#endregion
private System.Windows.Forms.GroupBox PortGroupBox;
diff --git a/Netch/Forms/SettingForm.cs b/Netch/Forms/SettingForm.cs
index 417ff934..d92ce54c 100644
--- a/Netch/Forms/SettingForm.cs
+++ b/Netch/Forms/SettingForm.cs
@@ -2,7 +2,9 @@
using System.IO;
using System.Linq;
using System.Net;
+using System.Threading.Tasks;
using System.Windows.Forms;
+using Netch.Controllers;
using Netch.Utils;
using TaskScheduler;
@@ -36,6 +38,7 @@ namespace Netch.Forms
TUNTAPUseCustomDNSCheckBox_CheckedChanged(null, null);
ProxyDNSCheckBox.Checked = Global.Settings.TUNTAP.ProxyDNS;
UseFakeDNSCheckBox.Checked = Global.Settings.TUNTAP.UseFakeDNS;
+ ICSCheckBox.Checked = ICSController.Enabled;
// Behavior
ExitWhenClosedCheckBox.Checked = Global.Settings.ExitWhenClosed;
@@ -64,7 +67,9 @@ namespace Netch.Forms
if (UseCustomDNSCheckBox.Checked)
{
- TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any() ? Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}") : "1.1.1.1";
+ TUNTAPDNSTextBox.Text = Global.Settings.TUNTAP.DNS.Any()
+ ? Global.Settings.TUNTAP.DNS.Aggregate((current, ip) => $"{current},{ip}")
+ : "1.1.1.1";
}
else
{
@@ -195,7 +200,8 @@ namespace Netch.Forms
if (UseCustomDNSCheckBox.Checked)
{
- dns = TUNTAPDNSTextBox.Text.Split(',').Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim()).ToArray();
+ dns = TUNTAPDNSTextBox.Text.Split(',').Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim())
+ .ToArray();
if (dns.Any())
{
foreach (var ip in dns)
@@ -401,5 +407,22 @@ namespace Netch.Forms
MessageBoxX.Show(i18N.Translate("Saved"));
Close();
}
+
+ private async void ICSCheckBox_CheckedChanged(object sender, EventArgs e)
+ {
+ ICSCheckBox.Enabled = false;
+ await Task.Run(() =>
+ {
+ if (ICSCheckBox.Checked)
+ {
+ ICSCheckBox.Checked = ICSController.Enable();
+ }
+ else
+ {
+ ICSController.Disable();
+ }
+ });
+ ICSCheckBox.Enabled = true;
+ }
}
}
\ No newline at end of file
diff --git a/Netch/Models/WinFW/NetworkConnection.cs b/Netch/Models/WinFW/NetworkConnection.cs
new file mode 100644
index 00000000..394b16ab
--- /dev/null
+++ b/Netch/Models/WinFW/NetworkConnection.cs
@@ -0,0 +1,114 @@
+using System;
+using NETCONLib;
+
+namespace WinFW
+{
+ public class NetworkConnection : INetConnection, INetConnectionProps, INetSharingConfiguration
+ {
+ private readonly INetConnection _icsConn;
+
+ private readonly NetSharingManager _icsMgr;
+
+ public NetworkConnection(INetConnection icsConnection)
+ {
+ _icsMgr = new NetSharingManagerClass();
+ _icsConn = icsConnection;
+ }
+
+ public void Connect()
+ {
+ _icsConn.Connect();
+ }
+
+ public void Delete()
+ {
+ _icsConn.Delete();
+ }
+
+ public void Duplicate(string pszwDuplicateName, out INetConnection ppCon)
+ {
+ _icsConn.Duplicate(pszwDuplicateName, out ppCon);
+ }
+
+ public void Disconnect()
+ {
+ _icsConn.Disconnect();
+ }
+
+ public void GetProperties(IntPtr ppProps)
+ {
+ _icsConn.GetProperties(ppProps);
+ }
+
+ public void Rename(string pszwNewName)
+ {
+ _icsConn.Rename(pszwNewName);
+ }
+
+ public void GetUiObjectClassId(out Guid pclsid)
+ {
+ _icsConn.GetUiObjectClassId(out pclsid);
+ }
+
+ public uint Characteristics => _icsMgr.NetConnectionProps[_icsConn].Characteristics;
+
+ public string DeviceName => _icsMgr.NetConnectionProps[_icsConn].DeviceName;
+
+ public string Guid => _icsMgr.NetConnectionProps[_icsConn].Guid;
+
+ public tagNETCON_MEDIATYPE MediaType => _icsMgr.NetConnectionProps[_icsConn].MediaType;
+
+ public string Name => _icsMgr.NetConnectionProps[_icsConn].Name;
+
+ public tagNETCON_STATUS Status => _icsMgr.NetConnectionProps[_icsConn].Status;
+
+ public INetSharingPortMapping AddPortMapping(string bstrName, byte ucIPProtocol, ushort usExternalPort,
+ ushort usInternalPort, uint dwOptions, string bstrTargetNameOrIPAddress, tagICS_TARGETTYPE eTargetType)
+ {
+ return _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].AddPortMapping(bstrName,
+ ucIPProtocol, usExternalPort, usInternalPort, dwOptions, bstrTargetNameOrIPAddress, eTargetType);
+ }
+
+ public void DisableInternetFirewall() => _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].DisableInternetFirewall();
+
+ public void DisableSharing()
+ {
+ _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].DisableSharing();
+ }
+
+ public void EnableInternetFirewall()
+ {
+ _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].EnableInternetFirewall();
+ }
+
+ public void EnableSharing(tagSHARINGCONNECTIONTYPE Type)
+ {
+ _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].EnableSharing(Type);
+ }
+
+ public void RemovePortMapping(INetSharingPortMapping pMapping)
+ {
+ _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].RemovePortMapping(pMapping);
+ }
+
+ public bool InternetFirewallEnabled =>
+ _icsMgr.INetSharingConfigurationForINetConnection[_icsConn]
+ .InternetFirewallEnabled;
+
+ public INetSharingPortMappingCollection get_EnumPortMappings(tagSHARINGCONNECTION_ENUM_FLAGS Flags)
+ {
+ return _icsMgr.INetSharingConfigurationForINetConnection[_icsConn]
+ .EnumPortMappings[Flags];
+ }
+
+ public tagSHARINGCONNECTIONTYPE SharingConnectionType =>
+ _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].SharingConnectionType;
+
+ public bool SharingEnabled => _icsMgr.INetSharingConfigurationForINetConnection[_icsConn].SharingEnabled;
+
+ public INetSharingConfiguration NetSharingConfigurationForINetConnection()
+ {
+ return _icsMgr.INetSharingConfigurationForINetConnection[_icsConn];
+ }
+ }
+}
\ No newline at end of file
diff --git a/Netch/Models/WinFW/NetworkConnectionCollection.cs b/Netch/Models/WinFW/NetworkConnectionCollection.cs
new file mode 100644
index 00000000..89ad9b3b
--- /dev/null
+++ b/Netch/Models/WinFW/NetworkConnectionCollection.cs
@@ -0,0 +1,201 @@
+using System.Collections;
+using System.Linq;
+using System.Management;
+using NETCONLib;
+
+namespace WinFW
+{
+ ///
+ /// A collection that stores 'NetworkConnection' objects.
+ ///
+ public class NetworkConnectionCollection : CollectionBase
+ {
+ ///
+ /// Initializes a new instance of 'NetworkConnectionCollection'.
+ ///
+ public NetworkConnectionCollection()
+ {
+ NetSharingManager icsMgr = new NetSharingManagerClass();
+
+ foreach (var icsConn in icsMgr.EnumEveryConnection.Cast())
+ {
+ Add(new NetworkConnection(icsConn));
+ }
+ }
+
+ ///
+ /// Represents the 'NetworkConnection' item at the specified index position.
+ ///
+ ///
+ /// The zero-based index of the entry to locate in the collection.
+ ///
+ ///
+ /// The entry at the specified index of the collection.
+ ///
+ public NetworkConnection this[int intIndex]
+ {
+ get => (NetworkConnection) List[intIndex];
+ set => List[intIndex] = value;
+ }
+
+ ///
+ /// Adds a 'NetworkConnection' item with the specified value to the 'NetworkConnectionCollection'
+ ///
+ ///
+ /// The 'NetworkConnection' to add.
+ ///
+ ///
+ /// The index at which the new element was inserted.
+ ///
+ public int Add(NetworkConnection conValue)
+ {
+ return List.Add(conValue);
+ }
+
+ ///
+ /// Copies the elements of an array at the end of this instance of 'NetworkConnectionCollection'.
+ ///
+ ///
+ /// An array of 'NetworkConnection' objects to add to the collection.
+ ///
+ public void AddRange(NetworkConnection[] conValue)
+ {
+ checked
+ {
+ foreach (var t in conValue)
+ Add(t);
+ }
+ }
+
+ ///
+ /// Adds the contents of another 'NetworkConnectionCollection' at the end of this instance.
+ ///
+ ///
+ /// A 'NetworkConnectionCollection' containing the objects to add to the collection.
+ ///
+ public void AddRange(NetworkConnectionCollection conValue)
+ {
+ checked
+ {
+ for (var intCounter = 0; intCounter < conValue.Count; intCounter++) Add(conValue[intCounter]);
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether the 'NetworkConnectionCollection' contains the specified value.
+ ///
+ ///
+ /// The item to locate.
+ ///
+ ///
+ /// True if the item exists in the collection; false otherwise.
+ ///
+ public bool Contains(NetworkConnection conValue)
+ {
+ return List.Contains(conValue);
+ }
+
+ ///
+ /// Copies the 'NetworkConnectionCollection' values to a one-dimensional System.Array
+ /// instance starting at the specified array index.
+ ///
+ ///
+ /// The one-dimensional System.Array that represents the copy destination.
+ ///
+ ///
+ /// The index in the array where copying begins.
+ ///
+ public void CopyTo(NetworkConnection[] conArray, int intIndex)
+ {
+ List.CopyTo(conArray, intIndex);
+ }
+
+ ///
+ /// Returns the index of a 'NetworkConnection' object in the collection.
+ ///
+ ///
+ /// The 'NetworkConnection' object whose index will be retrieved.
+ ///
+ ///
+ /// If found, the index of the value; otherwise, -1.
+ ///
+ public int IndexOf(NetworkConnection conValue)
+ {
+ return List.IndexOf(conValue);
+ }
+
+ ///
+ /// Inserts an existing 'NetworkConnection' into the collection at the specified index.
+ ///
+ ///
+ /// The zero-based index where the new item should be inserted.
+ ///
+ ///
+ /// The item to insert.
+ ///
+ public void Insert(int intIndex, NetworkConnection conValue)
+ {
+ List.Insert(intIndex, conValue);
+ }
+
+ ///
+ /// Returns an enumerator that can be used to iterate through
+ /// the 'NetworkConnectionCollection'.
+ ///
+ public new ConnectionEnumerator GetEnumerator()
+ {
+ return new ConnectionEnumerator(this);
+ }
+
+ ///
+ /// Removes a specific item from the 'NetworkConnectionCollection'.
+ ///
+ ///
+ /// The item to remove from the 'NetworkConnectionCollection'.
+ ///
+ public void Remove(NetworkConnection conValue)
+ {
+ List.Remove(conValue);
+ }
+
+ ///
+ /// A strongly typed enumerator for 'NetworkConnectionCollection'
+ ///
+ public class ConnectionEnumerator : IEnumerator
+ {
+ private readonly IEnumerator iEnBase;
+
+ private readonly IEnumerable iEnLocal;
+
+ ///
+ /// Enumerator constructor
+ ///
+ public ConnectionEnumerator(NetworkConnectionCollection conMappings)
+ {
+ iEnLocal = conMappings;
+ iEnBase = iEnLocal.GetEnumerator();
+ }
+
+ ///
+ /// Gets the current element from the collection
+ ///
+ public object Current => iEnBase.Current;
+
+ ///
+ /// Advances the enumerator to the next element of the collection
+ ///
+ public bool MoveNext()
+ {
+ return iEnBase.MoveNext();
+ }
+
+ ///
+ /// Sets the enumerator to the first element in the collection
+ ///
+ public void Reset()
+ {
+ iEnBase.Reset();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Netch/Netch.csproj b/Netch/Netch.csproj
index 0e931ebe..161fc70e 100644
--- a/Netch/Netch.csproj
+++ b/Netch/Netch.csproj
@@ -54,6 +54,14 @@
tlbimp
false
+
+ {43E734CA-043D-4A70-9A2C-A8F254063D91}
+ 1
+ 0
+ 0
+ tlbimp
+ False
+
@@ -73,6 +81,7 @@
+