fe2a6db786
rust / build / test / clippy / fmt (push) Has been cancelled
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>
183 lines
5.2 KiB
C#
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;
|
|
}
|
|
}
|