Vanara/UnitTests/PInvoke/IpHlpApi/IpHlpApiTests.cs

783 lines
30 KiB
C#

using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.IpHlpApi;
using static Vanara.PInvoke.Ws2_32;
namespace Vanara.PInvoke.Tests
{
public static class IPAddressExt
{
public static System.Net.IPAddress Convert(this SOCKET_ADDRESS sockAddr)
{
switch ((ADDRESS_FAMILY)Marshal.ReadInt16(sockAddr.lpSockaddr))
{
case ADDRESS_FAMILY.AF_INET:
return new System.Net.IPAddress((long)sockAddr.lpSockaddr.ToStructure<SOCKADDR_IN>().sin_addr);
case ADDRESS_FAMILY.AF_INET6:
return new System.Net.IPAddress(sockAddr.lpSockaddr.ToStructure<SOCKADDR_IN6>().sin6_addr);
default:
throw new Exception("Non-IP address family");
}
}
}
[TestFixture()]
public partial class IpHlpApiTests
{
private static readonly IntPtr NotifyData = new IntPtr(8943934);
private static SOCKADDR_IN localv4;
private static SOCKADDR_IN6 localv6;
private static IP_ADAPTER_ADDRESSES primaryAdapter;
private static SOCKADDR_IN LocalAddrV4 => localv4.sin_family == 0 ? (localv4 = primaryAdapter.UnicastAddresses.Select(r => r.Address.GetSOCKADDR()).First(a => a.si_family == ADDRESS_FAMILY.AF_INET).Ipv4) : localv4;
private static SOCKADDR_IN6 LocalAddrV6 => localv6.sin6_family == 0 ? (localv6 = primaryAdapter.UnicastAddresses.Select(r => r.Address.GetSOCKADDR()).First(a => a.si_family == ADDRESS_FAMILY.AF_INET6).Ipv6) : localv6;
[Test]
public void _StructSizeTest()
{
foreach (var s in typeof(Vanara.PInvoke.IpHlpApi).GetNestedStructSizes())
TestContext.WriteLine(s);
}
[Test]
public void AddDeleteIPAddressTest()
{
var newIp = new IN_ADDR(192, 168, 0, 252);
var mask = new IN_ADDR(255, 255, 255, 0);
#pragma warning disable CS0618 // Type or member is obsolete
Assert.That(AddIPAddress(newIp, mask, primaryAdapter.IfIndex, out var ctx, out var inst), Is.Zero);
#pragma warning restore CS0618 // Type or member is obsolete
Assert.That(DeleteIPAddress(ctx), Is.Zero);
}
[Test]
public void CreateDelPersistentTcpPortReservationTest()
{
const ushort start = 5000;
const ushort num = 20;
Assert.That(CreatePersistentTcpPortReservation(start, num, out var tok), Is.Zero);
Assert.That(LookupPersistentTcpPortReservation(start, num, out var tok2), Is.Zero);
Assert.That(tok, Is.EqualTo(tok2));
Assert.That(DeletePersistentTcpPortReservation(start, num), Is.Zero);
}
[Test]
public void CreateDelPersistentUdpPortReservationTest()
{
const ushort start = 5000;
const ushort num = 20;
Assert.That(CreatePersistentUdpPortReservation(start, num, out var tok), Is.Zero);
Assert.That(LookupPersistentUdpPortReservation(start, num, out var tok2), Is.Zero);
Assert.That(tok, Is.EqualTo(tok2));
Assert.That(DeletePersistentUdpPortReservation(start, num), Is.Zero);
}
// [Test] TODO - Figure out which parameters work
public void CreateDelProxyArpEntryTest()
{
var target = primaryAdapter.MulticastAddresses.First().Address.GetSOCKADDR().Ipv4.sin_addr; // new IN_ADDR(192, 168, 0, 202);
uint a = target.S_addr, m = 0x00FFFFFF, i = primaryAdapter.IfIndex;
Assert.That(CreateProxyArpEntry(a, m, i), Is.Zero);
Assert.That(DeleteProxyArpEntry(a, m, i), Is.Zero);
}
[Test]
public void CreateSetDeleteIpForwardEntryTest()
{
Assert.That(() =>
{
MIB_IPFORWARDROW row = default;
foreach (var rrow in GetIpForwardTable(true).Where(r => r.dwForwardDest == 0))
{
if (row.dwForwardType == 0) row = rrow;
DeleteIpForwardEntry(rrow).ThrowIfFailed();
}
row.dwForwardNextHop = 0xDDBBCCAA;
CreateIpForwardEntry(row).ThrowIfFailed();
//row.dwForwardProto = MIB_IPFORWARD_PROTO.MIB_IPPROTO_DHCP;
SetIpForwardEntry(row).ThrowIfFailed();
DeleteIpForwardEntry(row).ThrowIfFailed();
}, Throws.Nothing);
}
[Test]
public void CreateSetDeleteIpNetEntryTest()
{
var target = new IN_ADDR(192, 168, 0, 202);
Assert.That(GetBestRoute(target, 0, out var fwdRow), Is.Zero);
var mibrow = new MIB_IPNETROW(target, fwdRow.dwForwardIfIndex, SendARP(target), MIB_IPNET_TYPE.MIB_IPNET_TYPE_DYNAMIC);
MIB_IPNETTABLE t1 = null;
Assert.That(() => t1 = GetIpNetTable(true), Throws.Nothing);
if (t1 != null && HasVal(t1, mibrow))
Assert.That(DeleteIpNetEntry(mibrow), Is.Zero);
Assert.That(CreateIpNetEntry(mibrow), Is.Zero);
var t = GetIpNetTable(true);
Assert.That(HasVal(t, mibrow), Is.True);
Assert.That(SetIpNetEntry(mibrow), Is.Zero);
Assert.That(DeleteIpNetEntry(mibrow), Is.Zero);
var t3 = GetIpNetTable(true);
Assert.That(HasVal(t3, mibrow), Is.False);
bool HasVal(IEnumerable<MIB_IPNETROW> tb, MIB_IPNETROW r) =>
tb.Any(tr => tr.dwAddr.S_addr == r.dwAddr.S_addr && tr.dwIndex == r.dwIndex && tr.bPhysAddr.SequenceEqual(r.bPhysAddr));
}
[Test]
public void DisableRestoreMediaSenseTest()
{
var hEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
var pOverLapped = new System.Threading.NativeOverlapped { EventHandle = hEvent.SafeWaitHandle.DangerousGetHandle() };
unsafe
{
Assert.That(DisableMediaSense(out _, &pOverLapped), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING));
Assert.That(RestoreMediaSense(&pOverLapped, out _), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING));
}
}
[Test]
public void EnableUnenableRouterTest()
{
var hEvent = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
var pOverLapped = new System.Threading.NativeOverlapped { EventHandle = hEvent.SafeWaitHandle.DangerousGetHandle() };
unsafe
{
Assert.That(EnableRouter(out _, &pOverLapped), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING));
Assert.That(UnenableRouter(&pOverLapped, out _), Is.Zero.Or.EqualTo(Win32Error.ERROR_IO_PENDING));
}
}
[Test]
public void GetAdapterIndexTest()
{
const string prefix = "\\DEVICE\\TCPIP_";
Assert.That(GetAdapterIndex(prefix + primaryAdapter.AdapterName, out var idx), Is.Zero);
Assert.That(idx, Is.EqualTo(primaryAdapter.IfIndex));
Assert.That(GetAdapterIndex(primaryAdapter.AdapterName, out idx), Is.EqualTo(Win32Error.ERROR_FILE_NOT_FOUND));
Assert.That(GetAdapterIndex("__Bogus**__", out idx), Is.EqualTo(Win32Error.ERROR_INVALID_PARAMETER));
}
[Test]
public void GetAdapterOrderMapTest()
{
var map = GetAdapterOrderMap();
Assert.That(map, Is.Not.Null);
Assert.That(map.NumAdapters, Is.GreaterThan(0));
}
[Test]
public void GetAdaptersAddressesTest()
{
Assert.That(() =>
{
foreach (var addrs in GetAdaptersAddresses(GetAdaptersAddressesFlags.GAA_FLAG_INCLUDE_PREFIX, ADDRESS_FAMILY.AF_UNSPEC))
{
TestContext.WriteLine($"{addrs.IfIndex}) {addrs.AdapterName} ({addrs.FriendlyName});{addrs.Description};MAC:{PhysicalAddressToString(addrs.PhysicalAddress)}");
TestContext.WriteLine(" Uni:" + string.Join(";", addrs.UnicastAddresses.Select(a => a.Address)));
TestContext.WriteLine(" Any:" + string.Join(";", addrs.AnycastAddresses.Select(a => a.Address)));
TestContext.WriteLine(" MCS:" + string.Join(";", addrs.MulticastAddresses.Select(a => a.Address)));
TestContext.WriteLine(" DNS:" + string.Join(";", addrs.DnsServerAddresses.Select(a => a.Address)));
TestContext.WriteLine(" Prfx:" + string.Join(";", addrs.Prefixes.Select(a => a.Address)));
TestContext.WriteLine(" WINS:" + string.Join(";", addrs.WinsServerAddresses.Select(a => a.Address)));
TestContext.WriteLine(" GTWY:" + string.Join(";", addrs.GatewayAddresses.Select(a => a.Address)));
TestContext.WriteLine(" Sufx:" + string.Join(";", addrs.DnsSuffixes.Select(a => a.String)));
}
}, Throws.Nothing);
}
[Test]
public void GetAdaptersInfoTest()
{
uint len = 15000;
var mem = new SafeCoTaskMemHandle((int)len);
#pragma warning disable CS0618 // Type or member is obsolete
Assert.That(GetAdaptersInfo((IntPtr)mem, ref len), Is.Zero);
Assert.That(((IntPtr)mem).LinkedListToIEnum<IP_ADAPTER_INFO>(i => i.Next), Is.Not.Empty);
#pragma warning restore CS0618 // Type or member is obsolete
}
[Test]
public void GetBestInterfaceExTest()
{
#pragma warning disable CS0618 // Type or member is obsolete
var gw = primaryAdapter.GatewayAddresses.Select(a => a.Address.Convert()).FirstOrDefault();
#pragma warning restore CS0618 // Type or member is obsolete
var sa = new SOCKADDR(gw.GetAddressBytes(), 0, gw.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 0 : (uint)gw.ScopeId);
Assert.That(GetBestInterfaceEx(sa, out var idx), Is.Zero);
Assert.That(idx, Is.EqualTo(primaryAdapter.IfIndex));
}
[Test]
public void GetBestInterfaceTest()
{
#pragma warning disable CS0618 // Type or member is obsolete
var gw = (uint)primaryAdapter.GatewayAddresses.Select(a => a.Address.Convert()).FirstOrDefault().Address;
#pragma warning restore CS0618 // Type or member is obsolete
Assert.That(gw, Is.Not.Zero);
Assert.That(GetBestInterface(gw, out var idx), Is.Zero);
Assert.That(idx, Is.EqualTo(primaryAdapter.IfIndex));
}
[Test]
public void GetExtendedTcpTableTest()
{
Assert.That(() =>
{
var t1 = GetExtendedTcpTable<MIB_TCPTABLE>(TCP_TABLE_CLASS.TCP_TABLE_BASIC_ALL);
Assert.That(t1.dwNumEntries, Is.GreaterThan(0));
var t2 = GetExtendedTcpTable<MIB_TCPTABLE>(TCP_TABLE_CLASS.TCP_TABLE_BASIC_CONNECTIONS);
Assert.That(t2.dwNumEntries, Is.GreaterThan(0));
var t3 = GetExtendedTcpTable<MIB_TCPTABLE>(TCP_TABLE_CLASS.TCP_TABLE_BASIC_LISTENER);
Assert.That(t3.dwNumEntries, Is.GreaterThan(0));
var t4 = GetExtendedTcpTable<MIB_TCPTABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL);
Assert.That(t4.dwNumEntries, Is.GreaterThan(0));
var t5 = GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET6);
Assert.That(t5.dwNumEntries, Is.GreaterThan(0));
var t6 = GetExtendedTcpTable<MIB_TCPTABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_CONNECTIONS);
Assert.That(t6.dwNumEntries, Is.GreaterThan(0));
var t7 = GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_CONNECTIONS, ADDRESS_FAMILY.AF_INET6);
Assert.That(t7.dwNumEntries, Is.GreaterThan(0));
var t8 = GetExtendedTcpTable<MIB_TCPTABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_LISTENER);
Assert.That(t8.dwNumEntries, Is.GreaterThan(0));
var t9 = GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_LISTENER, ADDRESS_FAMILY.AF_INET6);
Assert.That(t9.dwNumEntries, Is.GreaterThan(0));
var t10 = GetExtendedTcpTable<MIB_TCPTABLE_OWNER_PID>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL);
Assert.That(t10.dwNumEntries, Is.GreaterThan(0));
var t11 = GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_PID>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, ADDRESS_FAMILY.AF_INET6);
Assert.That(t11.dwNumEntries, Is.GreaterThan(0));
var t12 = GetExtendedTcpTable<MIB_TCPTABLE_OWNER_PID>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_CONNECTIONS);
Assert.That(t12.dwNumEntries, Is.GreaterThan(0));
var t13 = GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_PID>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_CONNECTIONS, ADDRESS_FAMILY.AF_INET6);
Assert.That(t13.dwNumEntries, Is.GreaterThan(0));
var t14 = GetExtendedTcpTable<MIB_TCPTABLE_OWNER_PID>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER);
Assert.That(t14.dwNumEntries, Is.GreaterThan(0));
var t15 = GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_PID>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_LISTENER, ADDRESS_FAMILY.AF_INET6);
Assert.That(t15.dwNumEntries, Is.GreaterThan(0));
}, Throws.Nothing);
Assert.That(() => GetExtendedTcpTable<MIB_TCPTABLE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL), Throws.InvalidOperationException);
Assert.That(() => GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL), Throws.InvalidOperationException);
Assert.That(() => GetExtendedTcpTable<MIB_TCPTABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET6), Throws.InvalidOperationException);
}
[Test]
public void GetExtendedUdpTableTest()
{
Assert.That(() =>
{
var t1 = GetExtendedUdpTable<MIB_UDPTABLE>(UDP_TABLE_CLASS.UDP_TABLE_BASIC);
Assert.That(t1.dwNumEntries, Is.GreaterThan(0));
var t4 = GetExtendedUdpTable<MIB_UDPTABLE_OWNER_MODULE>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE);
Assert.That(t4.dwNumEntries, Is.GreaterThan(0));
var t5 = GetExtendedUdpTable<MIB_UDP6TABLE_OWNER_MODULE>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, ADDRESS_FAMILY.AF_INET6);
Assert.That(t5.dwNumEntries, Is.GreaterThan(0));
var t10 = GetExtendedUdpTable<MIB_UDPTABLE_OWNER_PID>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID);
Assert.That(t10.dwNumEntries, Is.GreaterThan(0));
TestContext.WriteLine("UDP PID: " + string.Join(",", t10.Select(t => t.dwOwningPid)));
var t11 = GetExtendedUdpTable<MIB_UDP6TABLE_OWNER_PID>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID, ADDRESS_FAMILY.AF_INET6);
Assert.That(t11.dwNumEntries, Is.GreaterThan(0));
TestContext.WriteLine("UDP6 PID: " + string.Join(",", t11.Select(t => t.dwOwningPid)));
}, Throws.Nothing);
Assert.That(() => GetExtendedUdpTable<MIB_UDPTABLE>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE), Throws.InvalidOperationException);
Assert.That(() => GetExtendedUdpTable<MIB_UDP6TABLE_OWNER_MODULE>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE), Throws.InvalidOperationException);
Assert.That(() => GetExtendedUdpTable<MIB_UDPTABLE_OWNER_MODULE>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, ADDRESS_FAMILY.AF_INET6), Throws.InvalidOperationException);
}
[Test]
public void GetFriendlyIfIndexTest()
{
Assert.That(GetFriendlyIfIndex(primaryAdapter.IfIndex), Is.Not.Zero);
}
[Test]
public void GetIcmpStatisticsTest()
{
Assert.That(GetIcmpStatistics(out var stat), Is.Zero);
Assert.That(stat.stats.icmpInStats.dwMsgs, Is.Not.Zero);
Assert.That(GetIcmpStatisticsEx(out var statx, ADDRESS_FAMILY.AF_INET), Is.Zero);
Assert.That(statx.icmpInStats.dwMsgs, Is.Not.Zero);
}
[Test]
public void GetIfTableTest()
{
Assert.That(() =>
{
var t = GetIfTable();
Assert.That(t.dwNumEntries, Is.GreaterThan(0));
foreach (var r in t)
{
var r2 = new MIB_IFROW(r.dwIndex);
Assert.That(GetIfEntry(ref r2), Is.Zero);
Assert.That(r.wszName, Is.EqualTo(r2.wszName));
Assert.That(SetIfEntry(r2), Is.Zero);
}
}, Throws.Nothing);
}
[Test]
public void GetInterfaceInfoTest()
{
Assert.That(() =>
{
var t = GetInterfaceInfo();
Assert.That(t.NumAdapters, Is.GreaterThan(0));
foreach (var r in t) ;
}, Throws.Nothing);
}
[Test]
public void GetIpAddrTableTest()
{
Assert.That(() =>
{
var t = GetIpAddrTable();
Assert.That(t.dwNumEntries, Is.GreaterThan(0));
foreach (var r in t) ;
}, Throws.Nothing);
}
[Test]
public void GetIpErrorStringTest()
{
var sz = 1024U;
var sb = new StringBuilder((int)sz);
Assert.That(GetIpErrorString(Win32Error.ERROR_CAN_NOT_COMPLETE, sb, ref sz), Is.Zero);
Assert.That(sb.Length, Is.GreaterThan(0));
}
[Test]
public void GetSetIpStatisticsTest()
{
Assert.That(GetIpStatistics(out var stat), Is.Zero);
Assert.That(stat.dwNumIf, Is.Not.Zero);
var sstat = new MIB_IPSTATS { Forwarding = MIB_IPSTATS_FORWARDING.MIB_USE_CURRENT_FORWARDING, dwDefaultTTL = stat.dwDefaultTTL + 1 };
Assert.That(SetIpStatisticsEx(sstat, ADDRESS_FAMILY.AF_INET), Is.Zero);
Assert.That(GetIpStatisticsEx(out var statx, ADDRESS_FAMILY.AF_INET), Is.Zero);
Assert.That(statx.dwDefaultTTL, Is.EqualTo(stat.dwDefaultTTL + 1));
sstat.dwDefaultTTL = stat.dwDefaultTTL;
Assert.That(SetIpStatistics(sstat), Is.Zero);
}
[Test]
public void GetNetworkParamsTest()
{
Assert.That(() =>
{
var t = GetNetworkParams();
Assert.That(t.HostName, Is.Not.Null);
}, Throws.Nothing);
}
[Test]
public void GetNumberOfInterfacesTest()
{
Assert.That(GetNumberOfInterfaces(out var num), Is.Zero);
Assert.That(num, Is.GreaterThan(0));
}
[Test]
public void GetOwnerModuleFromPidAndInfoTest()
{
foreach (var om in GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET6))
{
uint sz = 0;
var err = GetOwnerModuleFromPidAndInfo(om.dwOwningPid, om.OwningModuleInfo, TCPIP_OWNER_MODULE_INFO_CLASS.TCPIP_OWNER_MODULE_INFO_BASIC, IntPtr.Zero, ref sz);
TestContext.WriteLine($"{om.dwOwningPid} {string.Join(":", om.OwningModuleInfo)} {sz} {err}");
}
}
[Test]
public void GetOwnerModuleFromTcp6EntryTest()
{
Assert.That(() =>
{
foreach (var om in GetExtendedTcpTable<MIB_TCP6TABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET6, true))
{
try
{
var info = GetOwnerModuleFromTcp6Entry(om);
Assert.That(info.pModuleName, Is.Not.Null);
TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr}=>{om.ucRemoteAddr} {info.pModuleName}");
}
catch (Exception ex)
{
TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr}=>{om.ucRemoteAddr} {ex.HResult}");
//Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT()));
}
}
}, Throws.Nothing);
}
[Test]
public void GetOwnerModuleFromTcpEntryTest()
{
Assert.That(() =>
{
foreach (var om in GetExtendedTcpTable<MIB_TCPTABLE_OWNER_MODULE>(TCP_TABLE_CLASS.TCP_TABLE_OWNER_MODULE_ALL, ADDRESS_FAMILY.AF_INET, true))
{
try
{
var info = GetOwnerModuleFromTcpEntry(om);
Assert.That(info.pModuleName, Is.Not.Null);
TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr}=>{om.dwRemoteAddr} {info.pModuleName}");
}
catch (Exception ex)
{
TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr}=>{om.dwRemoteAddr} {ex.HResult}");
//Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT()));
}
}
}, Throws.Nothing);
}
[Test]
public void GetOwnerModuleFromUdp6EntryTest()
{
Assert.That(() =>
{
foreach (var om in GetExtendedUdpTable<MIB_UDP6TABLE_OWNER_MODULE>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, ADDRESS_FAMILY.AF_INET6))
{
try
{
var info = GetOwnerModuleFromUdp6Entry(om);
Assert.That(info.pModuleName, Is.Not.Null);
TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr} {info.pModuleName}");
}
catch (Exception ex)
{
TestContext.WriteLine($"{om.dwOwningPid} {om.ucLocalAddr} {ex.HResult}");
//Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT()));
}
}
}, Throws.Nothing);
}
[Test]
public void GetOwnerModuleFromUdpEntryTest()
{
Assert.That(() =>
{
foreach (var om in GetExtendedUdpTable<MIB_UDPTABLE_OWNER_MODULE>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_MODULE, ADDRESS_FAMILY.AF_INET))
{
try
{
var info = GetOwnerModuleFromUdpEntry(om);
Assert.That(info.pModuleName, Is.Not.Null);
TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr} {info.pModuleName}");
}
catch (Exception ex)
{
TestContext.WriteLine($"{om.dwOwningPid} {om.dwLocalAddr} {ex.HResult}");
//Assert.That(ex.HResult, Is.EqualTo(((Win32Error)Win32Error.ERROR_NOT_FOUND).ToHRESULT()));
}
}
}, Throws.Nothing);
}
[Test]
public void GetPerAdapterInfoTest()
{
Assert.That(() =>
{
var info = GetPerAdapterInfo(primaryAdapter.IfIndex);
Assert.That(info.DnsServerList, Is.Not.Empty);
}, Throws.Nothing);
}
[Test]
public void GetPerTcp6ConnectionEStatsTest()
{
var addr = LocalAddrV6.sin6_addr;
var row = GetTcp6Table(true).FirstOrDefault(r => r.LocalAddr == addr && r.dwLocalPort != 0 && r.dwRemotePort != 0);
Assert.That(row.LocalAddr != IN6_ADDR.Unspecified);
ToggleAllEstats(row, true);
foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE)))
{
if (type == TCP_ESTATS_TYPE.TcpConnectionEstatsSynOpts) continue;
Assert.That(GetPerTcp6ConnectionEStats(row, type, out var srw, out _, out _), ResultIs.Successful);
TestContext.Write(GetStats(srw));
}
ToggleAllEstats(row, false);
}
[Test]
public void GetPerTcpConnectionEStatsTest()
{
var addr = LocalAddrV4.sin_addr;
var row = GetTcpTable(true).FirstOrDefault(r => r.dwLocalAddr == addr && r.dwLocalPort != 0 && r.dwRemotePort != 0);
Assert.That(row, Is.Not.Null);
ToggleAllEstats(row, true);
foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE)))
{
if (type == TCP_ESTATS_TYPE.TcpConnectionEstatsSynOpts) continue;
Assert.That(GetPerTcpConnectionEStats(row, type, out var srw, out _, out _), ResultIs.Successful);
TestContext.Write(GetStats(srw));
}
ToggleAllEstats(row, false);
}
[Test]
public void GetRTTAndHopCountTest()
{
var target = new IN_ADDR(192, 168, 0, 202);
Assert.That(GetRTTAndHopCount(target, out var hops, uint.MaxValue, out var rtt), Is.True);
TestContext.WriteLine($"{target}: hops={hops} rtt={rtt}");
Assert.That(hops, Is.GreaterThan(0));
Assert.That(rtt, Is.GreaterThanOrEqualTo(0));
}
[Test]
public void GetTcpStatisticsTest()
{
Assert.That(GetTcpStatistics(out var stats), Is.Zero);
Assert.That(stats.dwNumConns, Is.GreaterThan(0));
}
[Test]
public void GetTcpStatisticsExTest()
{
Assert.That(GetTcpStatisticsEx(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero);
Assert.That(stats.dwNumConns, Is.GreaterThan(0));
}
[Test]
public void GetTcpStatisticsEx2Test()
{
Assert.That(GetTcpStatisticsEx2(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero);
Assert.That(stats.dwNumConns, Is.GreaterThan(0));
}
[Test]
public void GetUdpStatisticsTest()
{
Assert.That(GetUdpStatistics(out var stats), Is.Zero);
Assert.That(stats.dwNumAddrs, Is.GreaterThan(0));
}
[Test]
public void GetUdpStatisticsExTest()
{
Assert.That(GetUdpStatisticsEx(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero);
Assert.That(stats.dwNumAddrs, Is.GreaterThan(0));
}
[Test]
public void GetUdpStatisticsEx2Test()
{
Assert.That(GetUdpStatisticsEx2(out var stats, ADDRESS_FAMILY.AF_INET), Is.Zero);
Assert.That(stats.dwNumAddrs, Is.GreaterThan(0));
}
[Test]
public void GetUniDirectionalAdapterInfoTest()
{
Assert.That(() =>
{
var info = GetUniDirectionalAdapterInfo();
Assert.That(info.Address.Length, Is.GreaterThanOrEqualTo(0));
}, Throws.Nothing);
}
[Test]
public void IpReleaseRenewAddressTest()
{
var i = GetInterfaceInfo().First();
Assert.That(IpReleaseAddress(ref i), Is.Zero);
Assert.That(IpRenewAddress(ref i), Is.Zero);
var x = new IP_ADAPTER_INDEX_MAP() { Name = "Bogus" };
Assert.That(IpReleaseAddress(ref x), Is.EqualTo(Win32Error.ERROR_INVALID_PARAMETER));
Assert.That(IpRenewAddress(ref x), Is.EqualTo(Win32Error.ERROR_INVALID_PARAMETER));
}
// TODO: [Test]
public void NotifyAddrChangeTest()
{
throw new NotImplementedException();
}
// TODO: [Test]
public void NotifyRouteChangeTest()
{
throw new NotImplementedException();
}
[Test]
public void SendARPTest()
{
Assert.That(() =>
{
var gw = primaryAdapter.GatewayAddresses.Select(a => a.Address.Convert().GetAddressBytes()).FirstOrDefault();
var mac = SendARP(new IN_ADDR(gw));
Assert.That(mac.Length, Is.EqualTo(6));
Assert.That(mac, Has.Some.Not.EqualTo(0));
}, Throws.Nothing);
}
[SetUp]
public void Setup()
{
primaryAdapter = GetAdaptersAddresses(GetAdaptersAddressesFlags.GAA_FLAG_INCLUDE_GATEWAYS).FirstOrDefault(r => r.OperStatus == IF_OPER_STATUS.IfOperStatusUp && r.TunnelType == TUNNEL_TYPE.TUNNEL_TYPE_NONE && r.FirstGatewayAddress != IntPtr.Zero);
}
private static Win32Error CreateTcpConnection(bool v6, out SafeSOCKET serviceSocket, out SafeSOCKET clientSocket, out SOCKET acceptSocket, out ushort serverPort, out ushort clientPort)
{
Win32Error status;
var aiFamily = v6 ? ADDRESS_FAMILY.AF_INET6 : ADDRESS_FAMILY.AF_INET;
var hints = new ADDRINFOW
{
ai_family = aiFamily,
ai_socktype = SOCK.SOCK_STREAM,
ai_protocol = IPPROTO.IPPROTO_TCP
};
var loopback = v6 ? "::1" : "127.0.0.1";
serviceSocket = SafeSOCKET.INVALID_SOCKET;
clientSocket = SafeSOCKET.INVALID_SOCKET;
acceptSocket = SOCKET.INVALID_SOCKET;
serverPort = clientPort = 0;
status = GetAddrInfoW(loopback, "", hints, out var result);
if (status.Failed)
goto bail;
using (result)
{
var localhost = result.FirstOrDefault();
serviceSocket = socket(aiFamily, SOCK.SOCK_STREAM, IPPROTO.IPPROTO_TCP);
clientSocket = socket(aiFamily, SOCK.SOCK_STREAM, IPPROTO.IPPROTO_TCP);
if (serviceSocket == SOCKET.INVALID_SOCKET || clientSocket == SOCKET.INVALID_SOCKET)
goto bail;
status = (uint)bind(serviceSocket, localhost.addr, localhost.ai_addrlen);
if (status.Failed)
goto bail;
}
var serverSockName = SOCKADDR.Empty;
int nameLen = serverSockName.Size;
status = (uint)getsockname(serviceSocket, serverSockName, ref nameLen);
if (status.Failed)
goto bail;
serverPort = v6 ? ((SOCKADDR_IN6)serverSockName).sin6_port : ((SOCKADDR_IN)serverSockName).sin_port;
status = (uint)listen(serviceSocket, SOMAXCONN);
if (status.Failed)
goto bail;
status = (uint)connect(clientSocket, serverSockName, nameLen);
if (status.Failed)
goto bail;
var clientSockName = SOCKADDR.Empty;
nameLen = clientSockName.Size;
status = (uint)getsockname(clientSocket, clientSockName, ref nameLen);
if (status.Failed)
goto bail;
clientPort = v6 ? ((SOCKADDR_IN6)clientSockName).sin6_port : ((SOCKADDR_IN)clientSockName).sin_port;
acceptSocket = accept(serviceSocket);
if (acceptSocket == SOCKET.INVALID_SOCKET)
goto bail;
return Win32Error.ERROR_SUCCESS;
bail:
return status == SOCKET_ERROR ? WSAGetLastError() : status;
}
private static SafeAllocatedMemoryHandle GetRwForType(TCP_ESTATS_TYPE type, bool enable)
{
switch (type)
{
case TCP_ESTATS_TYPE.TcpConnectionEstatsData:
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_DATA_RW_v0 { EnableCollection = enable });
case TCP_ESTATS_TYPE.TcpConnectionEstatsSndCong:
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_SND_CONG_RW_v0 { EnableCollection = enable });
case TCP_ESTATS_TYPE.TcpConnectionEstatsPath:
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_PATH_RW_v0 { EnableCollection = enable });
case TCP_ESTATS_TYPE.TcpConnectionEstatsSendBuff:
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_SEND_BUFF_RW_v0 { EnableCollection = enable });
case TCP_ESTATS_TYPE.TcpConnectionEstatsRec:
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_REC_RW_v0 { EnableCollection = enable });
case TCP_ESTATS_TYPE.TcpConnectionEstatsObsRec:
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_OBS_REC_RW_v0 { EnableCollection = enable });
case TCP_ESTATS_TYPE.TcpConnectionEstatsBandwidth:
var operation = enable ? TCP_BOOLEAN_OPTIONAL.TcpBoolOptEnabled : TCP_BOOLEAN_OPTIONAL.TcpBoolOptDisabled;
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_BANDWIDTH_RW_v0 { EnableCollectionInbound = operation, EnableCollectionOutbound = operation });
case TCP_ESTATS_TYPE.TcpConnectionEstatsFineRtt:
return SafeHGlobalHandle.CreateFromStructure(new TCP_ESTATS_FINE_RTT_RW_v0 { EnableCollection = enable });
default:
return null;
}
}
private static string GetStats(object rw)
{
if (rw is null) return string.Empty;
var sb = new StringBuilder();
foreach (var fi in rw.GetType().GetFields())
sb.AppendLine($"{rw.GetType().Name}.{fi.Name} = {fi.GetValue(rw)}");
return sb.ToString();
}
private static void ToggleAllEstats(in MIB_TCP6ROW row, bool enable)
{
foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE)))
{
using (var mem = GetRwForType(type, enable))
if (mem != null)
SetPerTcp6ConnectionEStats(row, type, (IntPtr)mem, 0, (uint)mem.Size, 0);
}
}
private static void ToggleAllEstats(in MIB_TCPROW row, bool enable)
{
foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE)))
{
using (var mem = GetRwForType(type, enable))
if (mem != null)
SetPerTcpConnectionEStats(row, type, (IntPtr)mem, 0, (uint)mem.Size, 0);
}
}
//[Test] -- BROKEN
private void BrokenGetPerTcp6ConnectionEStatsTest()
{
CreateTcpConnection(true, out var serviceSocket, out var clientSocket, out var acceptSocket, out var serverPort, out var clientPort).ThrowIfFailed();
var serverConnectRow = GetTcp6Row(serverPort, clientPort, MIB_TCP_STATE.MIB_TCP_STATE_ESTAB);
var clientConnectRow = GetTcp6Row(clientPort, serverPort, MIB_TCP_STATE.MIB_TCP_STATE_ESTAB);
ToggleAllEstats(serverConnectRow, true);
ToggleAllEstats(clientConnectRow, true);
foreach (TCP_ESTATS_TYPE type in Enum.GetValues(typeof(TCP_ESTATS_TYPE)))
{
if (type == TCP_ESTATS_TYPE.TcpConnectionEstatsSynOpts) continue;
Assert.That(GetPerTcp6ConnectionEStats(serverConnectRow, type, out var srw, out _, out _), Is.Zero);
Console.Write(GetStats(srw));
Assert.That(GetPerTcp6ConnectionEStats(clientConnectRow, type, out var crw, out _, out _), Is.Zero);
Console.Write(GetStats(crw));
}
}
private MIB_TCP6ROW GetTcp6Row(ushort localPort, ushort remotePort, MIB_TCP_STATE state) =>
GetTcp6Table(true).First(r => r.dwLocalPort == localPort && r.dwRemotePort == remotePort && r.dwState == state);
private MIB_TCPROW GetTcpRow(ushort localPort, ushort remotePort, MIB_TCP_STATE state) =>
GetTcpTable(true).First(r => r.dwLocalPort == localPort && r.dwRemotePort == remotePort && r.dwState == state);
}
}