From efcd560dbd5cfbe600b201322f717526bf2de800 Mon Sep 17 00:00:00 2001 From: dahall Date: Mon, 11 May 2020 10:24:10 -0600 Subject: [PATCH] Added DnsGetCacheDataTable w/ unit test (#121) --- PInvoke/DnsApi/WinDns.Funcs.cs | 45 +++++++++++++++++++++++++++++++++ PInvoke/DnsApi/WinDns.cs | 20 +++++++++++++++ UnitTests/PInvoke/DnsApi/DnsApiTests.cs | 9 +++++++ 3 files changed, 74 insertions(+) diff --git a/PInvoke/DnsApi/WinDns.Funcs.cs b/PInvoke/DnsApi/WinDns.Funcs.cs index 9048eede..869c7f8e 100644 --- a/PInvoke/DnsApi/WinDns.Funcs.cs +++ b/PInvoke/DnsApi/WinDns.Funcs.cs @@ -200,6 +200,16 @@ namespace Vanara.PInvoke [PInvokeData("windns.h", MSDNShortId = "4c69d548-3bb5-4609-9fc5-3a829a285956")] public static extern void DnsFreeProxyName(IntPtr proxyName); + /// Gets a list of cached domain names in the DNS client. + /// The cached data list. + /// + /// Returns success confirmation upon successful completion. Otherwise, returns the appropriate DNS-specific error code as defined + /// in Winerror.h. + /// + [DllImport(Lib.Dnsapi, SetLastError = true, ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DnsGetCacheDataTable(out SafeDnsCacheDataTable ppCacheData); + /// /// The DnsGetProxyInformation function returns the proxy information for a DNS server's name resolution policy table. /// @@ -1327,6 +1337,41 @@ namespace Vanara.PInvoke public IntPtr DangerousGetHandle() => handle; } + /// Provides a for a list of allocated DNS_CACHE_ENTRY values that is disposed using . + public class SafeDnsCacheDataTable : SafeHANDLE, IEnumerable + { + /// Initializes a new instance of the class and assigns an existing handle. + /// An object that represents the pre-existing handle to use. + /// to reliably release the handle during the finalization phase; otherwise, (not recommended). + public SafeDnsCacheDataTable(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { } + + /// Initializes a new instance of the class. + private SafeDnsCacheDataTable() : base() { } + + /// Returns an enumerator that iterates through the collection. + /// A that can be used to iterate through the collection. + public IEnumerator GetEnumerator() => handle.LinkedListToIEnum(r => r.pNext).GetEnumerator(); + + /// Returns an enumerator that iterates through a collection. + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + /// + protected override bool InternalReleaseHandle() + { + // From https://stackoverflow.com/questions/31889957/memory-leak-when-using-dnsgetcachedatatable + var p = handle; + while (p != IntPtr.Zero) + { + var s = p.ToStructure(); + DnsFree((IntPtr)s.pszName, DNS_FREE_TYPE.DnsFreeFlat); + DnsFree(p, DNS_FREE_TYPE.DnsFreeFlat); + p = s.pNext; + } + return true; + } + } + /// Provides a for a DNS record list that is disposed using . public class SafeDnsRecordList : SafeHANDLE, IEnumerable { diff --git a/PInvoke/DnsApi/WinDns.cs b/PInvoke/DnsApi/WinDns.cs index 1062b660..e12b75d3 100644 --- a/PInvoke/DnsApi/WinDns.cs +++ b/PInvoke/DnsApi/WinDns.cs @@ -925,6 +925,26 @@ namespace Vanara.PInvoke public byte[] Address; } + /// Undocumented. + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct DNS_CACHE_ENTRY + { + /// Pointer to next entry. + public IntPtr pNext; + + /// DNS Record Name. + public StrPtrUni pszName; + + /// DNS Record Type. + public DNS_TYPE wType; + + /// Undocumented. + public ushort wDataLength; + + /// Undocumented. + public DNS_RECORD_FLAGS dwFlags; + } + /// /// The DNS_DHCID_DATA structure represents a DNS Dynamic Host Configuration Protocol Information (DHCID) resource record /// (RR) as specified in section 3 of RFC 4701. diff --git a/UnitTests/PInvoke/DnsApi/DnsApiTests.cs b/UnitTests/PInvoke/DnsApi/DnsApiTests.cs index 5d8fc655..00a3a246 100644 --- a/UnitTests/PInvoke/DnsApi/DnsApiTests.cs +++ b/UnitTests/PInvoke/DnsApi/DnsApiTests.cs @@ -30,6 +30,15 @@ namespace Vanara.PInvoke.Tests Assert.That(DnsExtractRecordsFromMessage(mem, (ushort)(uint)mem.Size, out var results), ResultIs.Successful); } + [Test] + public void DnsGetCacheDataTableTest() + { + Assert.That(DnsGetCacheDataTable(out var table), ResultIs.Successful); + foreach (var d in table) + TestContext.WriteLine($"{d.pszName} => {d.wType}"); + Assert.That(() => table.Dispose(), Throws.Nothing); + } + [Test] public void DnsGetProxyInformationTest() {