mirror of https://github.com/dahall/Vanara.git
783 lines
30 KiB
C#
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);
|
|
}
|
|
} |