From 79c906186c810d1465d92e7f976f4ad57b194949 Mon Sep 17 00:00:00 2001 From: dahall Date: Sat, 27 Jun 2020 18:42:50 -0600 Subject: [PATCH] Fixed problems with DNS struct alignment and added XML docs with tests --- PInvoke/DnsApi/WinDns.Funcs.cs | 4 +- PInvoke/DnsApi/WinDns.cs | 159 ++++++++++++++++++++++---------- UnitTests/PInvoke/DnsApi/DnsApi.csproj | 2 +- UnitTests/PInvoke/DnsApi/DnsApiTests.cs | 23 +++-- 4 files changed, 130 insertions(+), 58 deletions(-) diff --git a/PInvoke/DnsApi/WinDns.Funcs.cs b/PInvoke/DnsApi/WinDns.Funcs.cs index 869c7f8e..1e71d309 100644 --- a/PInvoke/DnsApi/WinDns.Funcs.cs +++ b/PInvoke/DnsApi/WinDns.Funcs.cs @@ -149,7 +149,7 @@ namespace Vanara.PInvoke // pCancelHandle ); [DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)] [PInvokeData("windns.h", MSDNShortId = "E5F422AA-D4E6-4F9F-A57C-608CE9317658")] - public static extern DNS_STATUS DnsCancelQuery(in DNS_QUERY_CANCEL pCancelHandle); + public static extern DNS_STATUS DnsCancelQuery(ref DNS_QUERY_CANCEL pCancelHandle); /// /// The DnsExtractRecordsFromMessage function type extracts resource records (RR) from a DNS message, and stores those @@ -687,7 +687,7 @@ namespace Vanara.PInvoke // pQueryRequest, PDNS_QUERY_RESULT pQueryResults, PDNS_QUERY_CANCEL pCancelHandle ); [DllImport(Lib.Dnsapi, SetLastError = false, ExactSpelling = true)] [PInvokeData("windns.h", MSDNShortId = "22664B9A-5010-42E7-880B-8D5B16A9F2DC")] - public static extern DNS_STATUS DnsQueryEx(in DNS_QUERY_REQUEST pQueryRequest, ref DNS_QUERY_RESULT pQueryResults, out DNS_QUERY_CANCEL pCancelHandle); + public static extern DNS_STATUS DnsQueryEx(in DNS_QUERY_REQUEST pQueryRequest, ref DNS_QUERY_RESULT pQueryResults, ref DNS_QUERY_CANCEL pCancelHandle); /// The DnsRecordCompare function compares two DNS resource records (RR). /// A pointer to a DNS_RECORD structure that contains the first DNS RR of the comparison pair. diff --git a/PInvoke/DnsApi/WinDns.cs b/PInvoke/DnsApi/WinDns.cs index a75a8f8f..0953f06c 100644 --- a/PInvoke/DnsApi/WinDns.cs +++ b/PInvoke/DnsApi/WinDns.cs @@ -129,12 +129,15 @@ namespace Vanara.PInvoke DnsConfigPrimaryDomainName_UTF8, /// Not currently available. + // Unimplemented DnsConfigAdapterDomainName_W, /// Not currently available. + // Unimplemented DnsConfigAdapterDomainName_A, /// Not currently available. + // Unimplemented DnsConfigAdapterDomainName_UTF8, /// For configuring a DNS Server list on Windows 2000. @@ -142,21 +145,23 @@ namespace Vanara.PInvoke DnsConfigDnsServerList, /// Not currently available. + // Unimplemented DnsConfigSearchList, /// Not currently available. + // Unimplemented DnsConfigAdapterInfo, /// Specifies that primary host name registration is enabled on Windows 2000. - [CorrespondingType(typeof(uint))] + // Unimplemented [CorrespondingType(typeof(uint))] DnsConfigPrimaryHostNameRegistrationEnabled, /// Specifies that adapter host name registration is enabled on Windows 2000. - [CorrespondingType(typeof(uint))] + // Unimplemented [CorrespondingType(typeof(uint))] DnsConfigAdapterHostNameRegistrationEnabled, /// Specifies configuration of the maximum number of address registrations on Windows 2000. - [CorrespondingType(typeof(uint))] + // Unimplemented [CorrespondingType(typeof(uint))] DnsConfigAddressRegistrationMaxCount, /// @@ -299,61 +304,105 @@ namespace Vanara.PInvoke [Flags] public enum DNS_QUERY_OPTIONS : uint { - /// + /// Standard query. DNS_QUERY_STANDARD = 0x00000000, - /// + /// Returns truncated results. Does not retry under TCP. DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 0x00000001, - /// + /// Uses TCP only for the query. DNS_QUERY_USE_TCP_ONLY = 0x00000002, - /// + /// + /// Directs the DNS server to perform an iterative query (specifically directs the DNS server not to perform recursive + /// resolution to resolve the query). + /// DNS_QUERY_NO_RECURSION = 0x00000004, - /// + /// Bypasses the resolver cache on the lookup. DNS_QUERY_BYPASS_CACHE = 0x00000008, - /// + /// + /// Directs DNS to perform a query on the local cache only.Windows 2000 Server and Windows 2000 Professional: This value is not + /// supported. For similar functionality, use DNS_QUERY_CACHE_ONLY. + /// DNS_QUERY_NO_WIRE_QUERY = 0x00000010, - /// + /// Directs DNS to ignore the local name.Windows 2000 Server and Windows 2000 Professional: This value is not supported. DNS_QUERY_NO_LOCAL_NAME = 0x00000020, - /// + /// + /// Prevents the DNS query from consulting the HOSTS file.Windows 2000 Server and Windows 2000 Professional: This value is not supported. + /// DNS_QUERY_NO_HOSTS_FILE = 0x00000040, - /// + /// + /// Prevents the DNS query from using NetBT for resolution.Windows 2000 Server and Windows 2000 Professional: This value is not supported. + /// DNS_QUERY_NO_NETBT = 0x00000080, - /// + /// + /// Directs DNS to perform a query using the network only, bypassing local information.Windows 2000 Server and Windows 2000 + /// Professional: This value is not supported. + /// DNS_QUERY_WIRE_ONLY = 0x00000100, - /// + /// + /// Directs DNS to return the entire DNS response message.Windows 2000 Server and Windows 2000 Professional: This value is not supported. + /// DNS_QUERY_RETURN_MESSAGE = 0x00000200, - /// + /// + /// Prevents the query from using DNS and uses only Local Link Multicast Name Resolution (LLMNR).Windows Vista and Windows + /// Server 2008 or later.: This value is supported. + /// DNS_QUERY_MULTICAST_ONLY = 0x00000400, /// DNS_QUERY_NO_MULTICAST = 0x00000800, - /// + /// Prevents the DNS response from attaching suffixes to the submitted name in a name resolution process. DNS_QUERY_TREAT_AS_FQDN = 0x00001000, - /// + /// + /// Windows 7 only: Do not send A type queries if IPv4 addresses are not available on an interface and do not send AAAA type + /// queries if IPv6 addresses are not available. + /// DNS_QUERY_ADDRCONFIG = 0x00002000, - /// + /// + /// Windows 7 only: Query both AAAA and A type records and return results for each. Results for A type records are mapped into + /// AAAA type. + /// DNS_QUERY_DUAL_ADDR = 0x00004000, /// Undocumented flag used by ipconfig to display DNS cache. DNS_QUERY_LOCAL = 0x00008000, - /// + /// + /// Waits for a full timeout to collect all the responses from the Local Link. If not set, the default behavior is to return + /// with the first response.Windows Vista and Windows Server 2008 or later.: This value is supported. + /// + DNS_QUERY_MULTICAST_WAIT = 0x00020000, + + /// + /// Directs a test using the local machine hostname to verify name uniqueness on the same Local Link.Collects all responses even + /// if normal LLMNR Sender behavior is not enabled.Windows Vista and Windows Server 2008 or later.: This value is supported. + /// + DNS_QUERY_MULTICAST_VERIFY = 0x00040000, + + /// + /// If set, and if the response contains multiple records, records are stored with the TTL corresponding to the minimum value + /// TTL from among all records. When this option is set, "Do not change the TTL of individual records" in the returned record + /// set is not modified. + /// DNS_QUERY_DONT_RESET_TTL_VALUES = 0x00100000, - /// + /// + /// Disables International Domain Name (IDN) encoding support in the DnsQuery, DnsQueryEx, DnsModifyRecordsInSet, and + /// DnsReplaceRecordSet APIs. All punycode names are treated as ASCII and will be ASCII encoded on the wire. All non-ASCII names + /// are encoded in UTF8 on the wire. Windows 8 or later.: This value is supported. + /// DNS_QUERY_DISABLE_IDN_ENCODING = 0x00200000, /// @@ -365,7 +414,7 @@ namespace Vanara.PInvoke /// DNS_QUERY_DNSSEC_CHECKING_DISABLED = 0x02000000, - /// + /// Reserved. DNS_QUERY_RESERVED = 0xf0000000, } @@ -704,37 +753,42 @@ namespace Vanara.PInvoke [Flags] public enum DNS_UPDATE : uint { - /// + /// Uses the default behavior, which is specified in the registry, for secure dynamic DNS updates. DNS_UPDATE_SECURITY_USE_DEFAULT = 0x00000000, - /// + /// Does not attempt secure dynamic updates. DNS_UPDATE_SECURITY_OFF = 0x00000010, - /// + /// Attempts non-secure dynamic update; if refused, attempts secure dynamic update. DNS_UPDATE_SECURITY_ON = 0x00000020, - /// + /// Attempts secure dynamic updates only. DNS_UPDATE_SECURITY_ONLY = 0x00000100, - /// + /// Caches the security context for use in future transactions. DNS_UPDATE_CACHE_SECURITY_CONTEXT = 0x00000200, - /// + /// Uses credentials of the local computer account. DNS_UPDATE_TEST_USE_LOCAL_SYS_ACCT = 0x00000400, - /// + /// Does not use cached security context. DNS_UPDATE_FORCE_SECURITY_NEGO = 0x00000800, - /// + /// Sends DNS updates to all multi-master DNS servers. DNS_UPDATE_TRY_ALL_MASTER_SERVERS = 0x00001000, - /// + /// + /// Do not update adapters where dynamic DNS updates are disabled. Windows 2000 Server with SP2 or later.: This value is supported. + /// DNS_UPDATE_SKIP_NO_UPDATE_ADAPTERS = 0x00002000, - /// + /// + /// Register CNAME records on a remote server in addition to the local DNS server.Windows 2000 Server with SP2 or later.: This + /// value is supported. + /// DNS_UPDATE_REMOTE_SERVER = 0x00004000, - /// + /// Reserved for future use. DNS_UPDATE_RESERVED = 0xffff0000, } @@ -1717,12 +1771,15 @@ namespace Vanara.PInvoke /// public DNS_TYPE QueryType; + // Hack to make this the right size even though the enum is a UInt32. + private ulong _QueryOptions; + /// /// A value that contains a bitmap of DNS Query Options to use in the DNS query. Options can be combined and all options /// override DNS_QUERY_STANDARD /// - public DNS_QUERY_OPTIONS QueryOptions; - + public DNS_QUERY_OPTIONS QueryOptions { get => (DNS_QUERY_OPTIONS)_QueryOptions; set => _QueryOptions = (ulong)value; } + /// Query options padding. public uint QueryOptionsHigh; @@ -1854,8 +1911,10 @@ namespace Vanara.PInvoke /// Reserved. Do not use. public uint dwReserved; - // The next entries are contrived so that the structure works on either 32 or 64 systems. The total size of the variable is 40 bytes on X86 and 56 on X64. + // The next entries are contrived so that the structure works on either 32 or 64 systems. The total size of the variable is 40 + // bytes on X86 and 56 on X64. private IntPtr _Data; + private IntPtr _fillPtr1; private IntPtr _fillPtr2; private IntPtr _fillPtr3; @@ -3052,11 +3111,11 @@ namespace Vanara.PInvoke /// A value representing the type of the records to be queried. See DNS_RECORD_TYPE for possible values. public DNS_TYPE QueryType; + // Hack to make this the right size even though the enum is a UInt32. + private ulong _QueryOptions; + /// A value representing the query options. DNS_QUERY_STANDARD is the only supported value. - public DNS_QUERY_OPTIONS QueryOptions; - - /// Query options padding. - public uint QueryOptionsHigh; + public DNS_QUERY_OPTIONS QueryOptions { get => (DNS_QUERY_OPTIONS)_QueryOptions; set => _QueryOptions = (ulong)value; } /// /// A value that contains the interface index over which the service is to be advertised. If is 0, then all interfaces will be considered. @@ -3159,16 +3218,11 @@ namespace Vanara.PInvoke } } - internal class PDNS_MESSAGE_BUFFER : SafeAnysizeStructBase - { - public PDNS_MESSAGE_BUFFER(IntPtr allocatedMemory, SizeT size) : base(allocatedMemory, size, false) { } - - protected override int GetArrayLength(in DNS_MESSAGE_BUFFER local) => Size - 12; - } - internal class DNS_MESSAGE_BUFFER_Marshaler : IVanaraMarshaler { - public DNS_MESSAGE_BUFFER_Marshaler() { } + public DNS_MESSAGE_BUFFER_Marshaler() + { + } SizeT IVanaraMarshaler.GetNativeSize() => Marshal.SizeOf(typeof(DNS_MESSAGE_BUFFER)); @@ -3182,6 +3236,15 @@ namespace Vanara.PInvoke } } + internal class PDNS_MESSAGE_BUFFER : SafeAnysizeStructBase + { + public PDNS_MESSAGE_BUFFER(IntPtr allocatedMemory, SizeT size) : base(allocatedMemory, size, false) + { + } + + protected override int GetArrayLength(in DNS_MESSAGE_BUFFER local) => Size - 12; + } + internal class SafeDNS_NSEC3_DATA : SafeAnysizeStructBase { internal SafeDNS_NSEC3_DATA(DNS_NSEC3_DATA value) : base(baseSz) @@ -3217,4 +3280,4 @@ namespace Vanara.PInvoke } } } -} +} \ No newline at end of file diff --git a/UnitTests/PInvoke/DnsApi/DnsApi.csproj b/UnitTests/PInvoke/DnsApi/DnsApi.csproj index e4021757..09041536 100644 --- a/UnitTests/PInvoke/DnsApi/DnsApi.csproj +++ b/UnitTests/PInvoke/DnsApi/DnsApi.csproj @@ -20,7 +20,7 @@ DEBUG;TRACE prompt 4 - x86 + AnyCPU true diff --git a/UnitTests/PInvoke/DnsApi/DnsApiTests.cs b/UnitTests/PInvoke/DnsApi/DnsApiTests.cs index 103a9daa..db21d377 100644 --- a/UnitTests/PInvoke/DnsApi/DnsApiTests.cs +++ b/UnitTests/PInvoke/DnsApi/DnsApiTests.cs @@ -74,7 +74,9 @@ namespace Vanara.PInvoke.Tests { var type = CorrespondingTypeAttribute.GetCorrespondingTypes(ctype, CorrespondingAction.GetSet).FirstOrDefault(); if (type is null || type == typeof(StrPtrAnsi)) Assert.Pass($"{ctype} Ignored"); - var sz = 1024U; + var sz = 0U; + var err = DnsQueryConfig(ctype, 0, null, default, default, ref sz); + Assert.That(sz, Is.GreaterThan(0U)); using var mem = new SafeCoTaskMemHandle(sz); Assert.That(DnsQueryConfig(ctype, 0, null, default, mem, ref sz), ResultIs.Successful); mem.DangerousGetHandle().Convert(sz, type, CharSet.Unicode).WriteValues(); @@ -84,23 +86,30 @@ namespace Vanara.PInvoke.Tests public void DnsQueryExTest() { using var evt = new System.Threading.AutoResetEvent(false); + var cancel = new DNS_QUERY_CANCEL(); var req = new DNS_QUERY_REQUEST { Version = DNS_QUERY_REQUEST_VERSION1, QueryName = dnsSvr, - QueryOptions = DNS_QUERY_OPTIONS.DNS_QUERY_STANDARD, + QueryOptions = DNS_QUERY_OPTIONS.DNS_QUERY_WIRE_ONLY | DNS_QUERY_OPTIONS.DNS_QUERY_BYPASS_CACHE, QueryType = DNS_TYPE.DNS_TYPE_ALL, pQueryCompletionCallback = Callback }; var res = new DNS_QUERY_RESULT { Version = DNS_QUERY_REQUEST_VERSION1 }; - Assert.That(DnsQueryEx(req, ref res, out var cancel), ResultIs.Value(Win32Error.DNS_REQUEST_PENDING)); - if (!evt.WaitOne(20000)) + var err = DnsQueryEx(req, ref res, ref cancel); + if (err == Win32Error.DNS_REQUEST_PENDING && !evt.WaitOne(20000)) { - Assert.That(DnsCancelQuery(cancel), ResultIs.Successful); + Assert.That(DnsCancelQuery(ref cancel), ResultIs.Successful); Assert.Fail("Completion callback not called."); } + else if (err.Failed) + Assert.Fail(err.ToString()); if (res.pQueryRecords != default) - DnsRecordListFree(res.pQueryRecords); + { + using var rlist = new SafeDnsRecordList(res.pQueryRecords); + foreach (var r in rlist) + r.WriteValues(); + } void Callback(IntPtr pQueryContext, ref DNS_QUERY_RESULT pQueryResults) { @@ -154,7 +163,7 @@ namespace Vanara.PInvoke.Tests Version = DNS_QUERY_REQUEST_VERSION1, Query = "_windns-example._udp.local", QueryType = DNS_TYPE.DNS_TYPE_PTR, - QueryOptions = DNS_QUERY_OPTIONS.DNS_QUERY_STANDARD, + QueryOptions = (ulong)DNS_QUERY_OPTIONS.DNS_QUERY_STANDARD, pQueryCallback = QueryCallback, pQueryContext = (IntPtr)evt };