Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
4af2fea
Move M365 exclusion routes into HTTP service to make it accessible ou…
ld0614 Apr 22, 2025
5ed3d7b
Update Copyright date in EULA
ld0614 May 11, 2025
477b5d0
Add simple interactive test endpoint for debugging. This should never…
ld0614 May 11, 2025
6ceff58
Added detection and removal for corrupted hiddenPBK files
ld0614 May 11, 2025
967a9f9
Increment build number as the beta version of 5.0.4 got rolled out to…
May 26, 2025
bf5959c
Avoid setting device tunnel related registry setting unless DPC 'owns…
ld0614 Jun 7, 2025
97b21cf
Merge branch 'Development' of https://github.com/ld0614/DPC into Deve…
ld0614 Jun 7, 2025
fa1e79c
Add support for Excluding DNS entries from force tunnel #26 and initi…
ld0614 Jun 7, 2025
b94ee5b
Avoid issues where multiple DNS entries return the same IP addresses
ld0614 Jul 23, 2025
c8348fb
Update Readme and bump dependencies
ld0614 Jul 26, 2025
a746d5c
Update ETW Library to fix issues with operational logs disappearing
ld0614 Jul 27, 2025
6743c25
Added ability to write logs to disk
ld0614 Jul 27, 2025
a3d1ed9
Fix Operational Events not showing in event log by forcing a reorgani…
ld0614 Jul 27, 2025
84f289f
Identified and fixed support for WMI profiles correctly identifying w…
ld0614 Jul 27, 2025
409e626
Update README in preperation for release
ld0614 Jul 27, 2025
e4b43af
Update README with Feature already added to the development branch
ld0614 Jul 27, 2025
980bf98
Refactor DNS lookups to continue in the event of a single resolution …
ld0614 Jul 27, 2025
52dc3b4
Bump Version Number
ld0614 Jul 27, 2025
019e0bc
Add tests for duplicate IP support and fix bug with DNS route comments
ld0614 Jul 27, 2025
98d7fe0
Update README
ld0614 Jul 27, 2025
a85d1a9
Clean up Dev Client
ld0614 Jul 27, 2025
74bbed2
Fix DNS route null exceptions
Jul 27, 2025
b8e5ed0
bump version number
Jul 27, 2025
46c8326
Attempt to avoid errors during the GPO update process by staggering p…
ld0614 Jul 29, 2025
031962d
Add additional Null Check
ld0614 Jul 29, 2025
3f882ec
Fix missing null check
ld0614 Jul 29, 2025
cc414d5
Add initial Get-RRASReport provided by ChrisAtWork on Discord
ld0614 Jul 29, 2025
d848317
Fix bug where thread was locked for profile update time
ld0614 Jul 30, 2025
fe1e7e7
Add debug event to show why a profile is being updated and prepare fo…
ld0614 Aug 10, 2025
85eb397
Update Development with Troubleshooting guide
ld0614 Aug 10, 2025
3995cc8
Merge branch 'Development' of https://github.com/ld0614/DPC into Deve…
ld0614 Aug 10, 2025
04b5425
Re-Merge from Main
ld0614 Aug 10, 2025
ad037d8
Merge branch 'main' into Development
ld0614 Aug 13, 2025
b874954
Update comments and fix capitalization
ld0614 Aug 13, 2025
b7142f4
Fixed issue with profile update never returning spinlock
ld0614 Aug 13, 2025
b8741ff
Merge branch 'main' into Development
ld0614 Aug 13, 2025
c12ba63
Pull 5.2.1 into IPv6 Dev Branch
ld0614 Aug 31, 2025
1b4ef33
Remove unused WMI Code
ld0614 Aug 31, 2025
b935b12
Updated proxy examples
Sep 5, 2025
f6a4540
Fix incorrect registry location for User Backup Tunnel Setting
ld0614 Sep 9, 2025
f419d19
Merge branch 'Development' into M365IPv6ExcludeList
ld0614 Sep 9, 2025
57a9185
Merge branch 'M365IPv6ExcludeList' of https://github.com/ld0614/DPC i…
ld0614 Sep 9, 2025
61237ed
Add identification of local IPv6 Gateway and associated Event Logs
ld0614 Sep 9, 2025
a889f4c
Start process of integrating with the local Route Table to dynamicall…
ld0614 Sep 9, 2025
974e11d
Fix null pointer exception
Sep 10, 2025
297b747
Add Event Handler to allow profiles to force an update when the local…
Sep 14, 2025
8faa048
Update interim changelog
ld0614 Sep 15, 2025
4a0514e
Merge branch 'Development' into M365IPv6ExcludeList
ld0614 Sep 15, 2025
35cec8e
Initialise the network state on startup and add additional logging
ld0614 Sep 15, 2025
35994e4
Moved GPO notifications into ProfileManager class to avoid needing a …
ld0614 Sep 15, 2025
abdc7a2
Moved excluded routes from warning to message in events
ld0614 Sep 15, 2025
697e7ff
Update development pipeline to run for all branches other than main
ld0614 Sep 15, 2025
2ccfa58
Remove unneeded route manipulation test code
ld0614 Sep 15, 2025
ea2648e
Remove references to exclusions being IPv4 only
ld0614 Sep 15, 2025
d9266c2
Move DNS Inclusion/Exclusion checks into profile load to avoid resolu…
ld0614 Sep 15, 2025
a2fd84d
Update PSExec Scripts to dynamically locate the latest version of the…
ld0614 Sep 16, 2025
e6a37a5
Update product version to differenciate it from live builds
Sep 17, 2025
5e67cfc
Merge branch 'M365IPv6ExcludeList' of https://github.com/ld0614/DPC i…
Sep 17, 2025
13e4723
Remove the filtering of link local gateways as these are commonly use…
ld0614 Sep 18, 2025
01608ec
bump version number
ld0614 Sep 18, 2025
4ac8806
add IP details to debug logs to assist with network interface related…
Sep 19, 2025
edb41ee
update dev client troubleshooting tool
Sep 19, 2025
78afd5c
Fix network interface selection
Sep 19, 2025
1e73a4d
Merge branch 'Development' into M365IPv6ExcludeList
ld0614 Sep 23, 2025
3b6adbd
Tests for and fixed #42
ld0614 Sep 23, 2025
a8c6435
Update Route to make use of existing IPUtil methods and add in additi…
ld0614 Sep 23, 2025
a59e070
update comment
ld0614 Sep 23, 2025
b49cdc9
Refactor of IP address validation logic (#44)
ryannewington Sep 24, 2025
629c284
Update interim change log
ld0614 Sep 24, 2025
c842bcb
Merge IPUtil changes into IPv6 branch
ld0614 Sep 24, 2025
d87f309
Bump version number
ld0614 Sep 24, 2025
d1ffb18
update new test to use network capability
ld0614 Sep 24, 2025
eba9d9d
Add additional null checks for proxy exclusions
ld0614 Sep 30, 2025
2ece02e
Prepare for release
ld0614 Sep 30, 2025
844a738
Merge branch 'main' into Development
ld0614 Sep 30, 2025
8d679a1
Merge 5.2.2 into IPv6 branch
ld0614 Sep 30, 2025
c82f318
update date formatting to a more standard method #47
ld0614 Nov 29, 2025
bf6ce2b
Enable service stopping for the shutdown event
ld0614 Dec 14, 2025
e596828
Add startup and shutdown events to the operational log to make troubl…
ld0614 Dec 14, 2025
74fb5cf
Merging logging changes into IPv6 Branch
ld0614 Dec 14, 2025
962804b
Update provisional release notes
ld0614 Dec 14, 2025
0bc1c93
Handle Windows not returning network interface details correctly #50
ld0614 Jan 18, 2026
1870d95
Bump version number for RC2
ld0614 Jan 18, 2026
4834858
Update version for release
ld0614 Jan 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions DPCDevClient/DPCDevClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
Expand All @@ -32,6 +33,9 @@
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>DPCDevClient.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand Down
38 changes: 35 additions & 3 deletions DPCDevClient/Program.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
using DPCLibrary.Utils;
using DPCLibrary.Enums;
using DPCLibrary.Utils;
using DPCService.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.NetworkInformation;

namespace DPCDevClient
{
internal class Program
{
static void Main(string[] args)
{
AddressChangedCallback(null, null);

NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(AddressChangedCallback);

string value;
do
{
Console.WriteLine("Startup Complete, Type 'quit' to Shutdown...");
value = Console.ReadLine();
} while (value.ToUpperInvariant() != "QUIT");
}

static void AddressChangedCallback(object sender, EventArgs e)
{
Console.WriteLine("Network change detected");

Console.WriteLine("All Gateway Settings");
IList<NetworkInterface> allAdapters = AccessNetInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface n in allAdapters)
{
Console.WriteLine("Name: {0}", n.Name);
Console.WriteLine(" Has IPv4 Gateway {0}", AccessNetInterface.InterfaceHasIPv4Gateway(n));
Console.WriteLine(" Has IPv6 Gateway {0}", AccessNetInterface.InterfaceHasIPv6Gateway(n));
}

Console.WriteLine("Local Gateway Settings");
IList<NetworkInterface> localAdapters = AccessNetInterface.GetLocalNetworkInterfaces();
foreach (NetworkInterface n in localAdapters)
{
Console.WriteLine("Name: {0}", n.Name);
Console.WriteLine(" Has IPv4 Gateway {0}", AccessNetInterface.InterfaceHasIPv4Gateway(n));
Console.WriteLine(" Has IPv6 Gateway {0}", AccessNetInterface.InterfaceHasIPv6Gateway(n));
}
}
}
}
6 changes: 0 additions & 6 deletions DPCInstaller/ADMX/en-US/DPC.adml
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,6 @@ NOTE: This is equivalent to nslookup and cannot account for related but unknown

NOTE: This option does not support wildcards

NOTE: This option only supports IPv4 address resolution

When a Forced Tunnel configuration is enabled this setting is ignored

'Value Name' should be the route to include
Expand All @@ -423,8 +421,6 @@ NOTE: This is equivalent to nslookup and cannot account for related but unknown

NOTE: This option does not support wildcards

NOTE: This option only supports IPv4 address resolution

When a Split Tunnel configuration is enabled this setting is ignored

'Value Name' should be the route to include
Expand Down Expand Up @@ -481,8 +477,6 @@ NOTE: When Register DNS is configured on the Machine Tunnel, this option is igno
<string id="DPCCategory_UserTunnel_ExcludeOffice365_Help">Office 365 traffic is often high bandwidth and communicating with a known and trusted source. These routes can change weekly so the exclusion list is dynamically generated by querying the Microsoft API.

NOTE: This option requires the device identity (not just the user) to have direct (unauthenticated) Internet access to https://endpoints.office.com. Currently a proxy is not supported with this option.

NOTE: This option only supports IPv4 address resolution
</string>
<string id="DPCCategory_UserTunnel_VPNStrategy">Optional - VPN Protocol</string>
<string id="DPCCategory_UserTunnel_VPNStrategy_Help">Specify the VPN Protocol to use and the order to fallback.
Expand Down
2 changes: 1 addition & 1 deletion DPCInstaller/ProductVersion.wxi
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<Include xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?define ProductVersion=5.2.2?>
<?define ProductVersion=5.3.0?>
</Include>
4 changes: 3 additions & 1 deletion DPCLibrary/DPCLibrary.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<ItemGroup>
<Compile Include="Enums\InterfaceOffloadFlags.cs" />
<Compile Include="Enums\IPAddressFamily.cs" />
<Compile Include="Enums\NetworkCapability.cs" />
<Compile Include="Enums\RasConnSubState.cs" />
<Compile Include="Enums\RasDialOptions.cs" />
<Compile Include="Enums\RasEapDialFlags.cs" />
Expand Down Expand Up @@ -127,7 +128,7 @@
<Compile Include="Models\IPv6Address.cs" />
<Compile Include="Models\Office365Exclusion.cs" />
<Compile Include="Models\OSVersion.cs" />
<Compile Include="Models\ProfileUpdate.cs" />
<Compile Include="Models\ManagedProfile.cs" />
<Compile Include="Models\RasConnection.cs" />
<Compile Include="Models\RasConstants.cs" />
<Compile Include="Models\RasEntry.cs" />
Expand All @@ -145,6 +146,7 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Utils\AccessFile.cs" />
<Compile Include="Utils\AccessNetInterface.cs" />
<Compile Include="Utils\AccessNetSh.cs" />
<Compile Include="Utils\AccessServices.cs" />
<Compile Include="Utils\AccessUserEnv.cs" />
Expand Down
10 changes: 10 additions & 0 deletions DPCLibrary/Enums/NetworkCapability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace DPCLibrary.Enums
{
public enum NetworkCapability
{
Unknown,
IPv4Only,
IPv6Only,
IPv4AndIpv6
}
}
File renamed without changes.
1 change: 1 addition & 0 deletions DPCLibrary/Models/RasConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static class RasConstants
public const int CNLEN = 15; //lmcons.h
public const int DNLEN = CNLEN; //lmcons.h
public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
public const int RTM_MAX_ADDRESS_SIZE = 16;

public const int MaxAdapterName = 128;
}
Expand Down
4 changes: 2 additions & 2 deletions DPCLibrary/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("D'Arcy Services Ltd")]
[assembly: AssemblyProduct("DPCLibrary")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -32,6 +32,6 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("4.0.*")]
[assembly: AssemblyVersion("5.0.*")]
[assembly: NeutralResourcesLanguage("en")]
//[assembly: AssemblyFileVersion("1.0.0.0")]
50 changes: 50 additions & 0 deletions DPCLibrary/Utils/AccessNetInterface.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;

namespace DPCLibrary.Utils
{
public static class AccessNetInterface
{
public static IList<NetworkInterface> GetAllNetworkInterfaces()
{
IList<NetworkInterface> adapters = NetworkInterface.GetAllNetworkInterfaces().ToList();
return adapters;
}

public static IList<NetworkInterface> GetLocalNetworkInterfaces()
{
IList<NetworkInterface> adapters = GetAllNetworkInterfaces().Where(ni => ni.OperationalStatus == OperationalStatus.Up &&
ni.NetworkInterfaceType != NetworkInterfaceType.Loopback &&
ni.NetworkInterfaceType != NetworkInterfaceType.Ppp ).ToList();
return adapters;
}

public static IList<NetworkInterface> GetVPNNetworkInterfaces()
{
IList<NetworkInterface> adapters = GetAllNetworkInterfaces().Where(ni => ni.NetworkInterfaceType == NetworkInterfaceType.Ppp).ToList();
return adapters;
}

private static IPAddress[] ValidGateways(NetworkInterface ni)
{
IPInterfaceProperties IPDetails = ni.GetIPProperties();
IPAddress[] validGateways = IPDetails.GatewayAddresses.Where(gw => !gw.Address.IsIPv6Multicast).Select(gw => gw.Address).ToArray();
return validGateways;
}

public static bool InterfaceHasIPv4Gateway(NetworkInterface ni)
{
IPAddress[] validGateways = ValidGateways(ni);
return validGateways.Where(gw => gw.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).Count() > 0;
}

public static bool InterfaceHasIPv6Gateway(NetworkInterface ni)
{
IPAddress[] validGateways = ValidGateways(ni);
return validGateways.Where(gw => gw.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6).Count() > 0;
}
}
}
57 changes: 0 additions & 57 deletions DPCLibrary/Utils/AccessWMI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,17 @@ public static class AccessWMI
private const string MDMWMINamespace = @"root\cimv2\mdm\dmmap";
private const string MDMWMIClassName = "MDM_VPNv2_01";
private const string NetAdapterWMINamespace = @"root\StandardCimv2";
private const string NetAdapterWMIClassName = "MSFT_NetAdapter";
private const string NetAdapterConfigWMINamespace = @"root\Cimv2";
private const string NetAdapterConfigWMIClassName = "Win32_NetworkAdapterConfiguration";
private const string NetInterfaceWMIClassName = "MSFT_NetIPInterface";
private const string RemoteAccessWMINamespace = @"root\Microsoft\Windows\RemoteAccess\Client";

private const string CSPURI = "./Vendor/MSFT/VPNv2";

public static IList<CimInstance> GetNetworkAdapters()
{
IEnumerable<CimInstance> NetAdapters = WMISession.EnumerateInstances(NetAdapterWMINamespace, NetAdapterWMIClassName);
return NetAdapters.ToList();
}

public static IList<CimInstance> GetNetIPInterfaces()
{
IEnumerable<CimInstance> NetAdapters = WMISession.EnumerateInstances(NetAdapterWMINamespace, NetInterfaceWMIClassName);
return NetAdapters.ToList();
}

public static IList<CimInstance> GetNetworkAdapterConfig()
{
IEnumerable<CimInstance> NetConfig = WMISession.EnumerateInstances(NetAdapterConfigWMINamespace, NetAdapterConfigWMIClassName);
return NetConfig.ToList();
}

//Can't use Getinstance as Name format is not understood (see Get-NetIPInterface | ft name, interfacealias, addressfamily), instead pull
//List of all interfaces and loop through them searching for the correct interface name
public static CimInstance GetNetIPInterface(string interfaceName, IPAddressFamily protocol)
Expand All @@ -69,48 +54,6 @@ public static CimInstance GetNetIPInterface(string interfaceName, IPAddressFamil
return null;
}

//Can't use Getinstance as Name format is not understood (see Get-NetIPInterface | ft name, interfacealias, addressfamily), instead pull
//List of all interfaces and loop through them searching for the correct interface name
public static uint? GetNetIPInterfaceIndex(string interfaceName, IPAddressFamily protocol)
{
IList<CimInstance> interfaces = GetNetIPInterfaces();
foreach (CimInstance instance in interfaces)
{
if ((string)instance.CimInstanceProperties["InterfaceAlias"].Value == interfaceName)
{
int familyInt = Convert.ToInt32(instance.CimInstanceProperties["AddressFamily"].Value, CultureInfo.InvariantCulture);
if ((IPAddressFamily)familyInt == protocol)
{
return Convert.ToUInt32(instance.CimInstanceProperties["InterfaceIndex"].Value, CultureInfo.InvariantCulture);
}
}
}

return null;
}

public static CimInstance GetNetAdapterConfig(string interfaceName, IPAddressFamily protocol)
{
CimInstance interfaceInstance = GetNetIPInterface(interfaceName, protocol);
if (interfaceInstance == null) return null;

return GetNetAdapterConfig(Convert.ToInt32(interfaceInstance.CimInstanceProperties["InterfaceIndex"].Value, CultureInfo.InvariantCulture));
}

public static CimInstance GetNetAdapterConfig(int interfaceIndex)
{
IList<CimInstance> adapters = GetNetworkAdapterConfig();
foreach (CimInstance instance in adapters)
{
if (Convert.ToInt32(instance.CimInstanceProperties["InterfaceIndex"].Value, CultureInfo.InvariantCulture) == interfaceIndex)
{
return instance;
}
}

return null;
}

public static uint? GetInterfaceMTU(string interfaceName, IPAddressFamily protocol)
{
CimInstance instance = GetNetIPInterface(interfaceName, protocol);
Expand Down
44 changes: 43 additions & 1 deletion DPCLibrary/Utils/HttpService.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using DPCLibrary.Models;
using DPCLibrary.Enums;
using DPCLibrary.Models;
using DPCLibrary.Singletons;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using IPAddress = System.Net.IPAddress;
Expand All @@ -13,6 +15,46 @@ public static class HttpService
{
private static bool breakNetwork = false; //Overridden in Tests - not a nice solution but simple without rewriting the entire network stack and removes the need for Microsoft Fakes (Enterprise Only)

/// <summary>
/// This method handles the core logic of preparing to get the latest Office 365 exclusion routes. The Microsoft endpoint requires a unique identifier
/// so we get it from registry if it already exists, if it doesn't we generate a new one and save it.
/// After we get the results from the HTTP Service we process the results to only return the results that DPC can handle. This is because the service
/// will return various types of result including URLs, wildcard URLs, IPv4 and IPv6 routes
/// </summary>
public static List<string> GetOffice365ExcludeRoutes()
{
Guid? nClientId = AccessRegistry.ReadMachineGuid(RegistrySettings.ClientId, RegistrySettings.InternalStateOffset);
Guid clientId;
if (nClientId == null)
{
clientId = Guid.NewGuid();
AccessRegistry.SaveMachineData(RegistrySettings.ClientId, clientId.ToString());
}
else
{
clientId = (Guid)nClientId;
}

Office365Exclusion[] Office365Endpoints = HttpService.GetOffice365EndPoints(clientId);
List<string[]> UsableIPList = Office365Endpoints.Where(e => e.Ips != null && e.Category == Office365EndpointCategory.Optimize).Select(e => e.Ips).ToList();
List<string> ipList = new List<string>();
foreach (string[] list in UsableIPList)
{
foreach (string item in list)
{
//Skip existing entries
if (ipList.Contains(item)) continue;

if (Validate.IPv4EndpointAddress(item) || Validate.IPv4CIDR(item) || Validate.IPv6EndpointAddress(item) || Validate.IPv6CIDR(item))
{
ipList.Add(item);
}
}
}

return ipList;
}

public static Office365Exclusion[] GetOffice365EndPoints(Guid clientId)
{
if (breakNetwork)
Expand Down
Loading