summaryrefslogtreecommitdiff
path: root/src/Agent.Windows/Diagnostics/WindowsPlatformCheck.cs
blob: 32086d3987b2887a40154197723c8208398f288d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using Agent.Windows.Security;
using Windows.Win32;
using Windows.Win32.NetworkManagement.WindowsFilteringPlatform;

namespace Agent.Windows.Diagnostics;

public sealed record WindowsPlatformCheckResult(
    bool PlatformSupported,
    bool ApplicationProfileAvailable,
    bool BfeEngineOpen,
    bool HelperAvailable,
    bool HelperVersionCompatible,
    int? ErrorCode,
    string? ErrorOperation)
{
    public bool Success => PlatformSupported && ApplicationProfileAvailable && BfeEngineOpen && HelperAvailable && HelperVersionCompatible;
}

public static class WindowsPlatformCheck
{
    public static WindowsPlatformCheckResult Run(string helperPath)
    {
        bool platform = OperatingSystem.IsWindowsVersionAtLeast(10, 0, 26100);
        bool profile = false;
        bool bfe = false;
        bool helper = File.Exists(helperPath);
        bool version = false;
        try
        {
            _ = AppContainerProfile.DeriveFixed();
            profile = true;
            using FwpmEngineClose0SafeHandle engine = OpenBfeReadOnly();
            bfe = true;
            if (helper)
            {
                Version? current = Assembly.GetEntryAssembly()?.GetName().Version;
                string candidate = FileVersionInfo.GetVersionInfo(helperPath).FileVersion ?? "";
                version = current is not null && HasSameReleaseIdentity(current, candidate);
            }
            return new(platform, profile, bfe, helper, version, null, null);
        }
        catch (Win32Exception ex) { return new(platform, profile, bfe, helper, version, ex.NativeErrorCode, ex.Message); }
        catch (Exception ex) when (ex is UnauthorizedAccessException or InvalidOperationException or IOException)
        { return new(platform, profile, bfe, helper, version, ex.HResult, ex.Message); }
    }

    internal static bool HasSameReleaseIdentity(Version current, string candidate)
    {
        if (!Version.TryParse(candidate, out Version? parsed)) return false;
        return current.Major == parsed.Major && current.Minor == parsed.Minor && current.Build == parsed.Build;
    }

    private static FwpmEngineClose0SafeHandle OpenBfeReadOnly()
    {
        uint result = PInvoke.FwpmEngineOpen0(10, null, null, out FwpmEngineClose0SafeHandle engine);
        if (result != 0) throw new Win32Exception(unchecked((int)result), $"FwpmEngineOpen0 failed with WFP/Win32 error 0x{result:X8}.");
        return engine;
    }
}