From f61437bc443130219f9da7fe5b6723499c60ed84 Mon Sep 17 00:00:00 2001 From: HeavenVR Date: Tue, 31 Mar 2026 14:50:13 +0200 Subject: [PATCH 1/6] Suggestion for implementation --- .../workflows/update-cloudflare-proxies.yml | 18 ++----- Common/Common.csproj | 51 ++++++++++++++++--- Common/Utils/CloudflareNetworks.g.cs | 33 ++++++++++++ Common/Utils/TrustedProxiesFetcher.cs | 11 +--- Common/cloudflare-ips.txt | 22 -------- 5 files changed, 84 insertions(+), 51 deletions(-) create mode 100644 Common/Utils/CloudflareNetworks.g.cs delete mode 100644 Common/cloudflare-ips.txt diff --git a/.github/workflows/update-cloudflare-proxies.yml b/.github/workflows/update-cloudflare-proxies.yml index 9f9bb8e6..38713713 100644 --- a/.github/workflows/update-cloudflare-proxies.yml +++ b/.github/workflows/update-cloudflare-proxies.yml @@ -5,9 +5,6 @@ on: - cron: '0 0 1 * *' # runs at 00:00 UTC on the 1st day of every month workflow_dispatch: -env: - IP_MERGED_FILE: Common/cloudflare-ips.txt - jobs: update-proxies: runs-on: ubuntu-latest @@ -17,23 +14,16 @@ jobs: with: ref: ${{ github.ref }} - - name: Fetch Cloudflare IPs and Update Files - env: - IPV4_URL: https://www.cloudflare.com/ips-v4 - IPV6_URL: https://www.cloudflare.com/ips-v6 - run: | - set -euo pipefail + - uses: actions/setup-dotnet@v4 - echo "Fetching Cloudflare IP lists and merging" - curl -s $IPV4_URL > $IP_MERGED_FILE - echo "" >> $IP_MERGED_FILE - curl -s $IPV6_URL >> $IP_MERGED_FILE + - name: Build to regenerate Cloudflare IPs + run: dotnet build Common/Common.csproj - name: Commit and Push Changes run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add ${{ env.IP_MERGED_FILE }} + git add Common/Utils/CloudflareNetworks.g.cs if git diff --cached --quiet; then echo "No changes detected." diff --git a/Common/Common.csproj b/Common/Common.csproj index 8c6c3174..86b88c76 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -35,12 +35,51 @@ - - - - Never - - + + + + + + + + + (); + lines.AddRange(File.ReadAllLines(IPv4File).Where(l => !string.IsNullOrWhiteSpace(l))); + lines.AddRange(File.ReadAllLines(IPv6File).Where(l => !string.IsNullOrWhiteSpace(l))); + + var sb = new System.Text.StringBuilder(); + sb.AppendLine("// "); + sb.AppendLine("using System.Net;"); + sb.AppendLine(); + sb.AppendLine("namespace OpenShock.Common.Utils;"); + sb.AppendLine(); + sb.AppendLine("public static partial class TrustedProxiesFetcher"); + sb.AppendLine("{"); + sb.AppendLine(" private static readonly IPNetwork[] CloudflareNetworks ="); + sb.AppendLine(" ["); + foreach (var line in lines) + sb.AppendLine($" IPNetwork.Parse(\"{line.Trim()}\"),"); + sb.AppendLine(" ];"); + sb.AppendLine("}"); + + File.WriteAllText(OutputFile, sb.ToString()); + ]]> + + + + + + + + + diff --git a/Common/Utils/CloudflareNetworks.g.cs b/Common/Utils/CloudflareNetworks.g.cs new file mode 100644 index 00000000..06e328fb --- /dev/null +++ b/Common/Utils/CloudflareNetworks.g.cs @@ -0,0 +1,33 @@ +// +using System.Net; + +namespace OpenShock.Common.Utils; + +public static partial class TrustedProxiesFetcher +{ + private static readonly IPNetwork[] CloudflareNetworks = + [ + IPNetwork.Parse("173.245.48.0/20"), + IPNetwork.Parse("103.21.244.0/22"), + IPNetwork.Parse("103.22.200.0/22"), + IPNetwork.Parse("103.31.4.0/22"), + IPNetwork.Parse("141.101.64.0/18"), + IPNetwork.Parse("108.162.192.0/18"), + IPNetwork.Parse("190.93.240.0/20"), + IPNetwork.Parse("188.114.96.0/20"), + IPNetwork.Parse("197.234.240.0/22"), + IPNetwork.Parse("198.41.128.0/17"), + IPNetwork.Parse("162.158.0.0/15"), + IPNetwork.Parse("104.16.0.0/13"), + IPNetwork.Parse("104.24.0.0/14"), + IPNetwork.Parse("172.64.0.0/13"), + IPNetwork.Parse("131.0.72.0/22"), + IPNetwork.Parse("2400:cb00::/32"), + IPNetwork.Parse("2606:4700::/32"), + IPNetwork.Parse("2803:f800::/32"), + IPNetwork.Parse("2405:b500::/32"), + IPNetwork.Parse("2405:8100::/32"), + IPNetwork.Parse("2a06:98c0::/29"), + IPNetwork.Parse("2c0f:f248::/32"), + ]; +} diff --git a/Common/Utils/TrustedProxiesFetcher.cs b/Common/Utils/TrustedProxiesFetcher.cs index 1a3142e9..bc1bc087 100644 --- a/Common/Utils/TrustedProxiesFetcher.cs +++ b/Common/Utils/TrustedProxiesFetcher.cs @@ -2,7 +2,7 @@ namespace OpenShock.Common.Utils; -public static class TrustedProxiesFetcher +public static partial class TrustedProxiesFetcher { private static readonly HttpClient Client = new(); @@ -77,14 +77,7 @@ public static async Task GetTrustedNetworksAsync(bool fetch = true) cfProxies = await FetchCloudflareIPs(); } - if (cfProxies is null) - { - var assembly = typeof(TrustedProxiesFetcher).Assembly; - var resourceName = assembly.GetName().Name + ".cloudflare-ips.txt"; - await using var stream = assembly.GetManifestResourceStream(resourceName) ?? throw new NullReferenceException("Could not open embedded cloudflare-ips.txt file"); - using var reader = new StreamReader(stream); - cfProxies = ParseNetworks(await reader.ReadToEndAsync()); - } + cfProxies ??= CloudflareNetworks; return [.. PrivateNetworksParsed, .. cfProxies]; } diff --git a/Common/cloudflare-ips.txt b/Common/cloudflare-ips.txt deleted file mode 100644 index fd160bd4..00000000 --- a/Common/cloudflare-ips.txt +++ /dev/null @@ -1,22 +0,0 @@ -173.245.48.0/20 -103.21.244.0/22 -103.22.200.0/22 -103.31.4.0/22 -141.101.64.0/18 -108.162.192.0/18 -190.93.240.0/20 -188.114.96.0/20 -197.234.240.0/22 -198.41.128.0/17 -162.158.0.0/15 -104.16.0.0/13 -104.24.0.0/14 -172.64.0.0/13 -131.0.72.0/22 -2400:cb00::/32 -2606:4700::/32 -2803:f800::/32 -2405:b500::/32 -2405:8100::/32 -2a06:98c0::/29 -2c0f:f248::/32 \ No newline at end of file From 593a0d50d5a9072450a64c0dfdd9319eda5f7e66 Mon Sep 17 00:00:00 2001 From: HeavenVR Date: Fri, 24 Apr 2026 18:27:08 +0200 Subject: [PATCH 2/6] Polish --- .../workflows/update-cloudflare-proxies.yml | 6 +++-- Common/Common.csproj | 23 +++++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/update-cloudflare-proxies.yml b/.github/workflows/update-cloudflare-proxies.yml index 38713713..6e7191a7 100644 --- a/.github/workflows/update-cloudflare-proxies.yml +++ b/.github/workflows/update-cloudflare-proxies.yml @@ -15,9 +15,11 @@ jobs: ref: ${{ github.ref }} - uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json - - name: Build to regenerate Cloudflare IPs - run: dotnet build Common/Common.csproj + - name: Regenerate Cloudflare IPs source + run: dotnet build Common/Common.csproj -p:UpdateCloudflareIPs=true - name: Commit and Push Changes run: | diff --git a/Common/Common.csproj b/Common/Common.csproj index 86b88c76..654f7f6a 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -35,8 +35,13 @@ - - + + @@ -68,14 +73,22 @@ - + + DestinationFileName="cf-v4.txt" + SkipUnchangedFiles="true" + Retries="3" + RetryDelayMilliseconds="2000" /> + DestinationFileName="cf-v6.txt" + SkipUnchangedFiles="true" + Retries="3" + RetryDelayMilliseconds="2000" /> From f2648fe7de3c6f363fdf569a0f79f8a63e67b184 Mon Sep 17 00:00:00 2001 From: HeavenVR Date: Fri, 24 Apr 2026 18:30:57 +0200 Subject: [PATCH 3/6] Run on file change --- .github/workflows/update-cloudflare-proxies.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/update-cloudflare-proxies.yml b/.github/workflows/update-cloudflare-proxies.yml index 6e7191a7..dcc7cfa1 100644 --- a/.github/workflows/update-cloudflare-proxies.yml +++ b/.github/workflows/update-cloudflare-proxies.yml @@ -4,6 +4,10 @@ on: schedule: - cron: '0 0 1 * *' # runs at 00:00 UTC on the 1st day of every month workflow_dispatch: + push: + paths: + - '.github/workflows/update-cloudflare-proxies.yml' + - 'Common/Common.csproj' jobs: update-proxies: From 117a5f5292509a8454351eecf9af3361dd3c4fee Mon Sep 17 00:00:00 2001 From: HeavenVR Date: Fri, 24 Apr 2026 19:08:57 +0200 Subject: [PATCH 4/6] Pre-Parse IP's --- Common/Common.csproj | 87 ++++++++++++++++++++++-- Common/Utils/CloudflareNetworks.g.cs | 98 +++++++++++++++++++++------- 2 files changed, 157 insertions(+), 28 deletions(-) diff --git a/Common/Common.csproj b/Common/Common.csproj index 654f7f6a..14485b45 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -49,12 +49,54 @@ (); - lines.AddRange(File.ReadAllLines(IPv4File).Where(l => !string.IsNullOrWhiteSpace(l))); - lines.AddRange(File.ReadAllLines(IPv6File).Where(l => !string.IsNullOrWhiteSpace(l))); + var v4Bytes = File.ReadAllBytes(IPv4File); + var v6Bytes = File.ReadAllBytes(IPv6File); + string v4Hash, v6Hash; + using (var sha256 = System.Security.Cryptography.SHA256.Create()) + { + v4Hash = System.BitConverter.ToString(sha256.ComputeHash(v4Bytes)).Replace("-", "").ToLowerInvariant(); + v6Hash = System.BitConverter.ToString(sha256.ComputeHash(v6Bytes)).Replace("-", "").ToLowerInvariant(); + } + + // Skip regen entirely if the existing file already reflects the same upstream content. + // Keeps timestamp/commit stable so the workflow only commits on real IP-list changes. + if (File.Exists(OutputFile)) + { + var existing = File.ReadAllText(OutputFile); + if (existing.Contains($"// IPv4 SHA256: {v4Hash}") && existing.Contains($"// IPv6 SHA256: {v6Hash}")) + { + Log.LogMessage(Microsoft.Build.Framework.MessageImportance.High, + "Cloudflare IP lists unchanged (SHA256 match); preserving existing CloudflareNetworks.g.cs."); + } + else + { + WriteGeneratedFile(); + } + } + else + { + WriteGeneratedFile(); + } + + void WriteGeneratedFile() + { + // Every non-empty line from Cloudflare is expected to be a valid CIDR. + // File.ReadAllLines handles the trailing newline; any blank/malformed line + // will fail the validation below with a FormatException. + var lines = File.ReadAllLines(IPv4File).Concat(File.ReadAllLines(IPv6File)).ToList(); + + var timestamp = System.DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ", System.Globalization.CultureInfo.InvariantCulture); var sb = new System.Text.StringBuilder(); - sb.AppendLine("// "); + sb.AppendLine("// "); + sb.AppendLine("// DO NOT EDIT - manual changes are overwritten on the next regeneration."); + sb.AppendLine("// "); + sb.AppendLine("// Cloudflare public proxy IP ranges (https://www.cloudflare.com/ips), baked in as a startup fallback for TrustedProxiesFetcher when the live fetch at application start fails or times out."); + sb.AppendLine("// Regenerated by the FetchCloudflareIPs target in Common.csproj, gated on -p:UpdateCloudflareIPs=true. The Update Cloudflare Proxies GitHub workflow is the only caller that passes that flag."); + sb.AppendLine("// "); + sb.AppendLine($"// Generated: {timestamp}"); + sb.AppendLine($"// IPv4 SHA256: {v4Hash}"); + sb.AppendLine($"// IPv6 SHA256: {v6Hash}"); sb.AppendLine("using System.Net;"); sb.AppendLine(); sb.AppendLine("namespace OpenShock.Common.Utils;"); @@ -64,11 +106,46 @@ sb.AppendLine(" private static readonly IPNetwork[] CloudflareNetworks ="); sb.AppendLine(" ["); foreach (var line in lines) - sb.AppendLine($" IPNetwork.Parse(\"{line.Trim()}\"),"); + { + var slash = line.IndexOf('/'); + if (slash < 0) + throw new System.FormatException($"Cloudflare IP entry '{line}' is missing the '/prefix' suffix."); + + var addressPart = line.Substring(0, slash); + var prefixPart = line.Substring(slash + 1); + + if (!int.TryParse(prefixPart, out var prefix)) + throw new System.FormatException($"Cloudflare IP entry '{line}' has a non-integer prefix '{prefixPart}'."); + + var bytes = System.Net.IPAddress.Parse(addressPart).GetAddressBytes(); + var inv = System.Globalization.CultureInfo.InvariantCulture; + + string address; + if (bytes.Length == 4) + { + // IPAddress(long) packs octet 0 in the low byte, octet 3 in the high byte. + long value = (long)bytes[0] + | ((long)bytes[1] << 8) + | ((long)bytes[2] << 16) + | ((long)bytes[3] << 24); + address = $"new IPAddress(0x{value.ToString("x8", inv)}L)"; + } + else + { + // IPAddress(ReadOnlySpan) — 16 bytes as hex pairs for readability. + var byteList = string.Join(", ", bytes.Select(b => "0x" + b.ToString("x2", inv))); + address = $"new IPAddress([{byteList}])"; + } + + sb.AppendLine($" // {line}"); + sb.AppendLine($" new IPNetwork({address}, prefixLength: {prefix}),"); + sb.AppendLine(); + } sb.AppendLine(" ];"); sb.AppendLine("}"); File.WriteAllText(OutputFile, sb.ToString()); + } ]]> diff --git a/Common/Utils/CloudflareNetworks.g.cs b/Common/Utils/CloudflareNetworks.g.cs index 06e328fb..5682c2a0 100644 --- a/Common/Utils/CloudflareNetworks.g.cs +++ b/Common/Utils/CloudflareNetworks.g.cs @@ -1,4 +1,12 @@ -// +// +// DO NOT EDIT - manual changes are overwritten on the next regeneration. +// +// Cloudflare public proxy IP ranges (https://www.cloudflare.com/ips), baked in as a startup fallback for TrustedProxiesFetcher when the live fetch at application start fails or times out. +// Regenerated by the FetchCloudflareIPs target in Common.csproj, gated on -p:UpdateCloudflareIPs=true. The Update Cloudflare Proxies GitHub workflow is the only caller that passes that flag. +// +// Generated: 2026-04-24T17:08:34Z +// IPv4 SHA256: f02c6d83bc01ab0ae8577160e036d700c7455359bce054df884e5d7d9e4e9e7b +// IPv6 SHA256: 9e9d39e3e83bad00c4decafd53c63fa62029f3d95db68de937d2be28234ca0a9 using System.Net; namespace OpenShock.Common.Utils; @@ -7,27 +15,71 @@ public static partial class TrustedProxiesFetcher { private static readonly IPNetwork[] CloudflareNetworks = [ - IPNetwork.Parse("173.245.48.0/20"), - IPNetwork.Parse("103.21.244.0/22"), - IPNetwork.Parse("103.22.200.0/22"), - IPNetwork.Parse("103.31.4.0/22"), - IPNetwork.Parse("141.101.64.0/18"), - IPNetwork.Parse("108.162.192.0/18"), - IPNetwork.Parse("190.93.240.0/20"), - IPNetwork.Parse("188.114.96.0/20"), - IPNetwork.Parse("197.234.240.0/22"), - IPNetwork.Parse("198.41.128.0/17"), - IPNetwork.Parse("162.158.0.0/15"), - IPNetwork.Parse("104.16.0.0/13"), - IPNetwork.Parse("104.24.0.0/14"), - IPNetwork.Parse("172.64.0.0/13"), - IPNetwork.Parse("131.0.72.0/22"), - IPNetwork.Parse("2400:cb00::/32"), - IPNetwork.Parse("2606:4700::/32"), - IPNetwork.Parse("2803:f800::/32"), - IPNetwork.Parse("2405:b500::/32"), - IPNetwork.Parse("2405:8100::/32"), - IPNetwork.Parse("2a06:98c0::/29"), - IPNetwork.Parse("2c0f:f248::/32"), + // 173.245.48.0/20 + new IPNetwork(new IPAddress(0x0030f5adL), prefixLength: 20), + + // 103.21.244.0/22 + new IPNetwork(new IPAddress(0x00f41567L), prefixLength: 22), + + // 103.22.200.0/22 + new IPNetwork(new IPAddress(0x00c81667L), prefixLength: 22), + + // 103.31.4.0/22 + new IPNetwork(new IPAddress(0x00041f67L), prefixLength: 22), + + // 141.101.64.0/18 + new IPNetwork(new IPAddress(0x0040658dL), prefixLength: 18), + + // 108.162.192.0/18 + new IPNetwork(new IPAddress(0x00c0a26cL), prefixLength: 18), + + // 190.93.240.0/20 + new IPNetwork(new IPAddress(0x00f05dbeL), prefixLength: 20), + + // 188.114.96.0/20 + new IPNetwork(new IPAddress(0x006072bcL), prefixLength: 20), + + // 197.234.240.0/22 + new IPNetwork(new IPAddress(0x00f0eac5L), prefixLength: 22), + + // 198.41.128.0/17 + new IPNetwork(new IPAddress(0x008029c6L), prefixLength: 17), + + // 162.158.0.0/15 + new IPNetwork(new IPAddress(0x00009ea2L), prefixLength: 15), + + // 104.16.0.0/13 + new IPNetwork(new IPAddress(0x00001068L), prefixLength: 13), + + // 104.24.0.0/14 + new IPNetwork(new IPAddress(0x00001868L), prefixLength: 14), + + // 172.64.0.0/13 + new IPNetwork(new IPAddress(0x000040acL), prefixLength: 13), + + // 131.0.72.0/22 + new IPNetwork(new IPAddress(0x00480083L), prefixLength: 22), + + // 2400:cb00::/32 + new IPNetwork(new IPAddress([0x24, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), prefixLength: 32), + + // 2606:4700::/32 + new IPNetwork(new IPAddress([0x26, 0x06, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), prefixLength: 32), + + // 2803:f800::/32 + new IPNetwork(new IPAddress([0x28, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), prefixLength: 32), + + // 2405:b500::/32 + new IPNetwork(new IPAddress([0x24, 0x05, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), prefixLength: 32), + + // 2405:8100::/32 + new IPNetwork(new IPAddress([0x24, 0x05, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), prefixLength: 32), + + // 2a06:98c0::/29 + new IPNetwork(new IPAddress([0x2a, 0x06, 0x98, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), prefixLength: 29), + + // 2c0f:f248::/32 + new IPNetwork(new IPAddress([0x2c, 0x0f, 0xf2, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), prefixLength: 32), + ]; } From 699a4806bf6865228abf1189f2be83ed08c662cd Mon Sep 17 00:00:00 2001 From: HeavenVR Date: Fri, 24 Apr 2026 19:12:51 +0200 Subject: [PATCH 5/6] update --- .../workflows/update-cloudflare-proxies.yml | 2 +- Common/CloudflareIPs.targets | 137 ++++++++++++++++++ Common/Common.csproj | 136 +---------------- 3 files changed, 139 insertions(+), 136 deletions(-) create mode 100644 Common/CloudflareIPs.targets diff --git a/.github/workflows/update-cloudflare-proxies.yml b/.github/workflows/update-cloudflare-proxies.yml index dcc7cfa1..2accda5d 100644 --- a/.github/workflows/update-cloudflare-proxies.yml +++ b/.github/workflows/update-cloudflare-proxies.yml @@ -7,7 +7,7 @@ on: push: paths: - '.github/workflows/update-cloudflare-proxies.yml' - - 'Common/Common.csproj' + - 'Common/CloudflareIPs.targets' jobs: update-proxies: diff --git a/Common/CloudflareIPs.targets b/Common/CloudflareIPs.targets new file mode 100644 index 00000000..afd006a6 --- /dev/null +++ b/Common/CloudflareIPs.targets @@ -0,0 +1,137 @@ + + + + + + + + + + "); + sb.AppendLine("// DO NOT EDIT - manual changes are overwritten on the next regeneration."); + sb.AppendLine("// "); + sb.AppendLine("// Cloudflare public proxy IP ranges (https://www.cloudflare.com/ips), baked in as a startup fallback for TrustedProxiesFetcher when the live fetch at application start fails or times out."); + sb.AppendLine("// Regenerated by the FetchCloudflareIPs target in Common.csproj, gated on -p:UpdateCloudflareIPs=true. The Update Cloudflare Proxies GitHub workflow is the only caller that passes that flag."); + sb.AppendLine("// "); + sb.AppendLine($"// Generated: {timestamp}"); + sb.AppendLine($"// IPv4 SHA256: {v4Hash}"); + sb.AppendLine($"// IPv6 SHA256: {v6Hash}"); + sb.AppendLine("using System.Net;"); + sb.AppendLine(); + sb.AppendLine("namespace OpenShock.Common.Utils;"); + sb.AppendLine(); + sb.AppendLine("public static partial class TrustedProxiesFetcher"); + sb.AppendLine("{"); + sb.AppendLine(" private static readonly IPNetwork[] CloudflareNetworks ="); + sb.AppendLine(" ["); + foreach (var line in lines) + { + var slash = line.IndexOf('/'); + if (slash < 0) + throw new System.FormatException($"Cloudflare IP entry '{line}' is missing the '/prefix' suffix."); + + var addressPart = line.Substring(0, slash); + var prefixPart = line.Substring(slash + 1); + + if (!int.TryParse(prefixPart, out var prefix)) + throw new System.FormatException($"Cloudflare IP entry '{line}' has a non-integer prefix '{prefixPart}'."); + + var bytes = System.Net.IPAddress.Parse(addressPart).GetAddressBytes(); + var inv = System.Globalization.CultureInfo.InvariantCulture; + + string address; + if (bytes.Length == 4) + { + // IPAddress(long) packs octet 0 in the low byte, octet 3 in the high byte. + long value = (long)bytes[0] + | ((long)bytes[1] << 8) + | ((long)bytes[2] << 16) + | ((long)bytes[3] << 24); + address = $"new IPAddress(0x{value.ToString("x8", inv)}L)"; + } + else + { + // IPAddress(ReadOnlySpan) — 16 bytes as hex pairs for readability. + var byteList = string.Join(", ", bytes.Select(b => "0x" + b.ToString("x2", inv))); + address = $"new IPAddress([{byteList}])"; + } + + sb.AppendLine($" // {line}"); + sb.AppendLine($" new IPNetwork({address}, prefixLength: {prefix}),"); + sb.AppendLine(); + } + sb.AppendLine(" ];"); + sb.AppendLine("}"); + + File.WriteAllText(OutputFile, sb.ToString()); + } + ]]> + + + + + + + + + + diff --git a/Common/Common.csproj b/Common/Common.csproj index 14485b45..a1eb241f 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -35,141 +35,7 @@ - - - - - - - - - "); - sb.AppendLine("// DO NOT EDIT - manual changes are overwritten on the next regeneration."); - sb.AppendLine("// "); - sb.AppendLine("// Cloudflare public proxy IP ranges (https://www.cloudflare.com/ips), baked in as a startup fallback for TrustedProxiesFetcher when the live fetch at application start fails or times out."); - sb.AppendLine("// Regenerated by the FetchCloudflareIPs target in Common.csproj, gated on -p:UpdateCloudflareIPs=true. The Update Cloudflare Proxies GitHub workflow is the only caller that passes that flag."); - sb.AppendLine("// "); - sb.AppendLine($"// Generated: {timestamp}"); - sb.AppendLine($"// IPv4 SHA256: {v4Hash}"); - sb.AppendLine($"// IPv6 SHA256: {v6Hash}"); - sb.AppendLine("using System.Net;"); - sb.AppendLine(); - sb.AppendLine("namespace OpenShock.Common.Utils;"); - sb.AppendLine(); - sb.AppendLine("public static partial class TrustedProxiesFetcher"); - sb.AppendLine("{"); - sb.AppendLine(" private static readonly IPNetwork[] CloudflareNetworks ="); - sb.AppendLine(" ["); - foreach (var line in lines) - { - var slash = line.IndexOf('/'); - if (slash < 0) - throw new System.FormatException($"Cloudflare IP entry '{line}' is missing the '/prefix' suffix."); - - var addressPart = line.Substring(0, slash); - var prefixPart = line.Substring(slash + 1); - - if (!int.TryParse(prefixPart, out var prefix)) - throw new System.FormatException($"Cloudflare IP entry '{line}' has a non-integer prefix '{prefixPart}'."); - - var bytes = System.Net.IPAddress.Parse(addressPart).GetAddressBytes(); - var inv = System.Globalization.CultureInfo.InvariantCulture; - - string address; - if (bytes.Length == 4) - { - // IPAddress(long) packs octet 0 in the low byte, octet 3 in the high byte. - long value = (long)bytes[0] - | ((long)bytes[1] << 8) - | ((long)bytes[2] << 16) - | ((long)bytes[3] << 24); - address = $"new IPAddress(0x{value.ToString("x8", inv)}L)"; - } - else - { - // IPAddress(ReadOnlySpan) — 16 bytes as hex pairs for readability. - var byteList = string.Join(", ", bytes.Select(b => "0x" + b.ToString("x2", inv))); - address = $"new IPAddress([{byteList}])"; - } - - sb.AppendLine($" // {line}"); - sb.AppendLine($" new IPNetwork({address}, prefixLength: {prefix}),"); - sb.AppendLine(); - } - sb.AppendLine(" ];"); - sb.AppendLine("}"); - - File.WriteAllText(OutputFile, sb.ToString()); - } - ]]> - - - - - - - - - + From e85b464b119d98ffb9b72cbc8b8c1e0b230fa030 Mon Sep 17 00:00:00 2001 From: HeavenVR Date: Fri, 24 Apr 2026 19:22:45 +0200 Subject: [PATCH 6/6] fix stuff --- .github/workflows/update-cloudflare-proxies.yml | 2 +- global.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-cloudflare-proxies.yml b/.github/workflows/update-cloudflare-proxies.yml index 2accda5d..6ed0e573 100644 --- a/.github/workflows/update-cloudflare-proxies.yml +++ b/.github/workflows/update-cloudflare-proxies.yml @@ -18,7 +18,7 @@ jobs: with: ref: ${{ github.ref }} - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@v5 with: global-json-file: global.json diff --git a/global.json b/global.json index 2e206e82..7cceb992 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "10.0.0", + "version": "10.0.100", "rollForward": "latestMinor", "allowPrerelease": false },