Files
Joseph Doherty fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
Initial project state: .NET reference, design, Rust port (M0+M1), evidence
Layout:
- src/                    .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
                          MxAsbClient, probes, tests, harnesses. Executable spec.
- design/                 Architectural plan for the Rust port (M0–M6), error
                          model, protocol invariants, risks (R1–R16), adversarial
                          review log (review.md).
- rust/                   Rust workspace. M0 skeleton + M1 codec parity.
                          mxaccess-codec: 215 unit tests + 2 cross-implementation
                          parity tests (byte-identical against .NET reference).
                          Other crates are M0 stubs awaiting M2+.
- captures/               Frida + netsh + pcap evidence per CLAUDE.md
                          ("captures are evidence, not throwaway logs").
- analysis/               Decompiled C# (frida/proxy/decompiled-*),
                          Ghidra exports for native DLLs (`exports/` only —
                          working state at `projects/` and AVEVA's input
                          binaries at `input/` are gitignored).
- docs/                   Reverse-engineering reference docs.
- tools/                  Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
                          Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/      Rust CI: fmt + build + test + clippy on Windows.
- LICENSE                 MIT (Joseph Doherty, 2026).

Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly

Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 06:21:00 -04:00

183 lines
5.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.ServiceModel.Discovery;
namespace ArchestrAServices.Common.Resolution;
public class Resolution
{
private static string MostRecentIPAddressFromExe;
[Obsolete("Use ArchestrAServices.Common.HostedService.Resolution.GetDiscoveryEndpointMetadata() instead.")]
public static EndpointDiscoveryMetadata GetDiscoveryEndpointMetada(EndpointDiscoveryMetadata metaData)
{
string errorMessage;
return GetDiscoveryEndpointMetada(metaData, out errorMessage);
}
[Obsolete("Use ArchestrAServices.Common.HostedService.Resolution.GetDiscoveryEndpointMetadata() instead.")]
public static EndpointDiscoveryMetadata GetDiscoveryEndpointMetada(EndpointDiscoveryMetadata metaData, out string errorMessage)
{
errorMessage = string.Empty;
try
{
if (metaData != null)
{
string[] array = null;
NetworkInterface[] array2 = null;
try
{
array2 = NetworkInterface.GetAllNetworkInterfaces();
}
catch (NetworkInformationException)
{
array2 = null;
}
if (array2 != null)
{
List<string> list = new List<string>();
NetworkInterface[] array3 = array2;
foreach (NetworkInterface networkInterface in array3)
{
if (networkInterface.NetworkInterfaceType != NetworkInterfaceType.Ethernet)
{
continue;
}
foreach (UnicastIPAddressInformation unicastAddress in networkInterface.GetIPProperties().UnicastAddresses)
{
if (unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork && unicastAddress.SuffixOrigin != SuffixOrigin.LinkLayerAddress)
{
if (unicastAddress.SuffixOrigin == SuffixOrigin.Manual || unicastAddress.SuffixOrigin == SuffixOrigin.OriginDhcp)
{
list.Insert(0, unicastAddress.Address.ToString());
}
else
{
list.Add(unicastAddress.Address.ToString());
}
}
}
}
list.Add(Environment.MachineName);
array = list.ToArray();
}
UriBuilder uriBuilder = new UriBuilder(metaData.Address.Uri);
if (uriBuilder != null && !string.IsNullOrEmpty(uriBuilder.Host))
{
metaData.ListenUris.Clear();
string[] array4 = array;
foreach (string host in array4)
{
uriBuilder.Host = host;
Uri uri = uriBuilder.Uri;
metaData.ListenUris.Add(uri);
}
}
}
}
catch (Exception ex2)
{
errorMessage = "GetDiscoveryEndpointMetada: Exception " + ex2.Message;
}
return metaData;
}
[Obsolete("Legacy method. No longer supported due to deprecated Win32 methods being used.")]
public static string ResolveIPAddress(string HostOrIP, out string errorMessage)
{
string empty = string.Empty;
errorMessage = string.Empty;
if (!Environment.Is64BitProcess)
{
try
{
empty = ResolveLocalIPAddr(HostOrIP, out errorMessage);
}
catch (Exception ex)
{
empty = string.Empty;
errorMessage = "ResolveIPAddress caught exception: " + ex.Message;
}
}
else
{
if (string.IsNullOrEmpty(MostRecentIPAddressFromExe))
{
string text = Guid.NewGuid().ToString() + "_Resolution";
using PipeServer pipeServer = new PipeServer(text);
if (File.Exists("aaASBResolveIP.exe"))
{
try
{
Process.Start("aaASBResolveIP.exe", text + " " + HostOrIP);
MostRecentIPAddressFromExe = pipeServer.ReadString();
}
catch (Exception ex2)
{
errorMessage = $"ResolveIPAddress called in 64-bit process - exception starting or reading from helper process aaASBResolveIP.exe: {ex2.Message}";
}
}
else
{
errorMessage = "ResolveIPAddress called in 64-bit process - could not find helper process aaASBResolveIP.exe, no resolution";
}
}
empty = MostRecentIPAddressFromExe;
}
return empty;
}
private unsafe static string ResolveLocalIPAddr(string HostOrIP, out string errorMessage)
{
WinSock.WSAData lpWSAData;
int num = WinSock.WSAStartup(514, out lpWSAData);
string result = string.Empty;
errorMessage = "Unknown failure in ResolveLocalIPAddr";
if (num == 0)
{
int addr = WinSock.inet_addr(HostOrIP);
WinSock.hostent* ptr = null;
if (addr != -1)
{
int len = 4;
ptr = WinSock.gethostbyaddr(ref addr, len, ProtocolFamily.InterNetwork);
if (ptr == null)
{
result = string.Empty;
errorMessage = "ResolveLocalIPAddr: call to gethostbyaddr for IP address " + HostOrIP + " failed to resolve a hostent struct";
}
}
else
{
ptr = WinSock.gethostbyname(HostOrIP);
if (ptr == null)
{
result = string.Empty;
errorMessage = "ResolveLocalIPAddr: call to gethostbyname for host name " + HostOrIP + " failed to resolve a hostent struct";
}
}
if (ptr != null)
{
byte* h_addr_list = *ptr->h_addr_list;
int num2 = *h_addr_list;
int num3 = h_addr_list[1];
int num4 = h_addr_list[2];
int num5 = h_addr_list[3];
result = $"{num2}.{num3}.{num4}.{num5}";
errorMessage = string.Empty;
}
WinSock.WSACleanup();
}
else
{
result = string.Empty;
errorMessage = "ResolveLocalIPAddr: unable to initialize WinSock, WSAStartup returned error";
}
return result;
}
}