dnsapi/tests: Test how DnsQuery() handles CNAMEs.
[wine.git] / dlls / dnsapi / tests / query.c
blob9b54aa3c81612e9031fa5b5dbd84bc7bdb55ce73
1 /*
2 * Copyright 2020 Dmitry Timoshkov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <stdio.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winnls.h"
25 #include "windns.h"
26 #include "winsock2.h"
27 #include "ws2ipdef.h"
28 #include "iphlpapi.h"
30 #include "wine/test.h"
32 #define NS_MAXDNAME 1025
34 static void test_DnsQuery(void)
36 WCHAR domain[MAX_PATH];
37 WCHAR name[NS_MAXDNAME];
38 DWORD ret, size;
39 DNS_RECORDW *rec, *ptr;
40 DNS_STATUS status;
41 WORD type;
43 rec = NULL;
44 status = DnsQuery_W(L"winehq.org", DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &rec, NULL);
45 if (status == ERROR_TIMEOUT)
47 skip("query timed out\n");
48 return;
50 ok(status == ERROR_SUCCESS, "got %ld\n", status);
51 DnsRecordListFree(rec, DnsFreeRecordList);
53 /* Show that DNS_TYPE_A returns CNAMEs too */
54 rec = NULL;
55 wcscpy(domain, L"test.winehq.org"); /* should be a CNAME */
56 status = DnsQuery_W(domain, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &rec, NULL);
57 if (status == ERROR_TIMEOUT)
59 skip("query timed out\n");
60 return;
62 ok(status == ERROR_SUCCESS, "got %ld\n", status);
63 type = DNS_TYPE_CNAME; /* CNAMEs come first */
64 for (ptr = rec; ptr; ptr = ptr->pNext)
66 ok(!wcscmp(domain, ptr->pName), "expected record name %s, got %s\n", wine_dbgstr_w(domain), wine_dbgstr_w(ptr->pName));
67 ok(type == ptr->wType, "expected record type %d, got %d\n", type, ptr->wType);
68 if (ptr->wType == DNS_TYPE_CNAME)
70 /* CNAME chains are bad practice so assume A for the remainder */
71 type = DNS_TYPE_A;
72 wcscpy(domain, L"winehq.org");
73 ok(!wcscmp(domain, ptr->Data.CNAME.pNameHost), "expected CNAME target %s, got %s\n", wine_dbgstr_w(domain), wine_dbgstr_w(ptr->Data.CNAME.pNameHost));
76 DnsRecordListFree(rec, DnsFreeRecordList);
78 /* But DNS_TYPE_CNAME does not return A records! */
79 rec = NULL;
80 wcscpy(domain, L"test.winehq.org");
81 status = DnsQuery_W(L"test.winehq.org", DNS_TYPE_CNAME, DNS_QUERY_STANDARD, NULL, &rec, NULL);
82 if (status == ERROR_TIMEOUT)
84 skip("query timed out\n");
85 return;
87 ok(status == ERROR_SUCCESS, "got %ld\n", status);
88 ptr = rec;
89 ok(!wcscmp(domain, ptr->pName), "expected record name %s, got %s\n", wine_dbgstr_w(domain), wine_dbgstr_w(ptr->pName));
90 ok(DNS_TYPE_CNAME == ptr->wType, "expected record type %d, got %d\n", DNS_TYPE_CNAME, ptr->wType);
91 if (ptr->wType == DNS_TYPE_CNAME)
93 wcscpy(domain, L"winehq.org");
94 ok(!wcscmp(domain, ptr->Data.CNAME.pNameHost), "expected CNAME target %s, got %s\n", wine_dbgstr_w(domain), wine_dbgstr_w(ptr->Data.CNAME.pNameHost));
96 ok(ptr->pNext == NULL, "unexpected CNAME chain\n");
97 DnsRecordListFree(rec, DnsFreeRecordList);
99 status = DnsQuery_W(L"", DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
100 ok(status == DNS_ERROR_RCODE_NAME_ERROR || status == DNS_INFO_NO_RECORDS || status == ERROR_INVALID_NAME /* XP */,
101 "got %ld\n", status);
103 wcscpy(domain, L"_ldap._tcp.deadbeef");
104 status = DnsQuery_W(domain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
105 ok(status == DNS_ERROR_RCODE_NAME_ERROR || status == DNS_INFO_NO_RECORDS || status == ERROR_INVALID_NAME /* XP */,
106 "got %ld\n", status);
108 wcscpy(domain, L"_ldap._tcp.dc._msdcs.");
109 size = ARRAY_SIZE(domain) - wcslen(domain);
110 ret = GetComputerNameExW(ComputerNameDnsDomain, domain + wcslen(domain), &size);
111 ok(ret, "GetComputerNameEx error %lu\n", GetLastError());
112 if (!size)
114 skip("computer is not in a domain\n");
115 return;
118 status = DnsQuery_W(domain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
119 trace("DnsQuery_W(%s) => %ld\n", wine_dbgstr_w(domain), status);
120 if (status != ERROR_SUCCESS)
122 skip("domain %s doesn't have an SRV entry\n", wine_dbgstr_w(domain));
123 return;
126 trace("target %s, port %d\n", wine_dbgstr_w(rec->Data.Srv.pNameTarget), rec->Data.Srv.wPort);
128 lstrcpynW(name, rec->Data.Srv.pNameTarget, ARRAY_SIZE(name));
129 DnsRecordListFree(rec, DnsFreeRecordList);
131 /* IPv4 */
132 status = DnsQuery_W(name, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &rec, NULL);
133 ok(status == ERROR_SUCCESS || status == DNS_ERROR_RCODE_NAME_ERROR, "DnsQuery_W(%s) => %ld\n",
134 wine_dbgstr_w(name), status);
135 if (status == ERROR_SUCCESS)
137 SOCKADDR_IN addr;
138 WCHAR buf[IP4_ADDRESS_STRING_LENGTH];
140 addr.sin_family = AF_INET;
141 addr.sin_port = 0;
142 addr.sin_addr.s_addr = rec->Data.A.IpAddress;
143 size = sizeof(buf);
144 ret = WSAAddressToStringW((SOCKADDR *)&addr, sizeof(addr), NULL, buf, &size);
145 ok(!ret, "WSAAddressToStringW error %lu\n", ret);
146 trace("WSAAddressToStringW => %s\n", wine_dbgstr_w(buf));
148 DnsRecordListFree(rec, DnsFreeRecordList);
151 /* IPv6 */
152 status = DnsQuery_W(name, DNS_TYPE_AAAA, DNS_QUERY_STANDARD, NULL, &rec, NULL);
153 ok(status == ERROR_SUCCESS || status == DNS_ERROR_RCODE_NAME_ERROR, "DnsQuery_W(%s) => %ld\n",
154 wine_dbgstr_w(name), status);
155 if (status == ERROR_SUCCESS)
157 SOCKADDR_IN6 addr;
158 WCHAR buf[IP6_ADDRESS_STRING_LENGTH];
160 addr.sin6_family = AF_INET6;
161 addr.sin6_port = 0;
162 addr.sin6_scope_id = 0;
163 memcpy(addr.sin6_addr.s6_addr, &rec->Data.AAAA.Ip6Address, sizeof(rec->Data.AAAA.Ip6Address));
164 size = sizeof(buf);
165 ret = WSAAddressToStringW((SOCKADDR *)&addr, sizeof(addr), NULL, buf, &size);
166 ok(!ret, "WSAAddressToStringW error %lu\n", ret);
167 trace("WSAAddressToStringW => %s\n", wine_dbgstr_w(buf));
169 DnsRecordListFree(rec, DnsFreeRecordList);
173 static IP_ADAPTER_ADDRESSES *get_adapters(void)
175 ULONG err, size = 1024;
176 IP_ADAPTER_ADDRESSES *ret = malloc( size );
177 for (;;)
179 err = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
180 GAA_FLAG_SKIP_FRIENDLY_NAME,
181 NULL, ret, &size );
182 if (err != ERROR_BUFFER_OVERFLOW) break;
183 ret = realloc( ret, size );
185 if (err == ERROR_SUCCESS) return ret;
186 free( ret );
187 return NULL;
190 static void test_DnsQueryConfig( void )
192 DNS_STATUS err;
193 DWORD size, i, ipv6_count;
194 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1];
195 IP_ADAPTER_ADDRESSES *adapters, *ptr;
196 DNS_ADDR_ARRAY *ipv4, *ipv6, *unspec;
197 IP4_ARRAY *ip4_array;
199 if (!(adapters = get_adapters())) return;
201 for (ptr = adapters; ptr; ptr = ptr->Next)
203 MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
204 if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
206 size = 0;
207 err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, NULL, &size );
208 if (err) continue;
209 ipv4 = malloc( size );
210 size--;
211 err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, ipv4, &size );
212 ok( err == ERROR_MORE_DATA, "got %ld\n", err );
213 size++;
214 err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, ipv4, &size );
215 ok( !err, "got %ld\n", err );
217 ok( ipv4->AddrCount == ipv4->MaxCount, "got %lu vs %lu\n", ipv4->AddrCount, ipv4->MaxCount );
218 ok( !ipv4->Tag, "got %#lx\n", ipv4->Tag );
219 ok( !ipv4->Family, "got %d\n", ipv4->Family );
220 ok( !ipv4->WordReserved, "got %#x\n", ipv4->WordReserved );
221 ok( !ipv4->Flags, "got %#lx\n", ipv4->Flags );
222 ok( !ipv4->MatchFlag, "got %#lx\n", ipv4->MatchFlag );
223 ok( !ipv4->Reserved1, "got %#lx\n", ipv4->Reserved1 );
224 ok( !ipv4->Reserved2, "got %#lx\n", ipv4->Reserved2 );
226 size = 0;
227 err = DnsQueryConfig( DnsConfigDnsServerList, 0, name, NULL, NULL, &size );
228 ok( !err, "got %ld\n", err );
229 ip4_array = malloc( size );
230 err = DnsQueryConfig( DnsConfigDnsServerList, 0, name, NULL, ip4_array, &size );
231 ok( !err, "got %ld\n", err );
233 ok( ipv4->AddrCount == ip4_array->AddrCount, "got %lu vs %lu\n", ipv4->AddrCount, ip4_array->AddrCount );
235 for (i = 0; i < ipv4->AddrCount; i++)
237 SOCKADDR_IN *sa = (SOCKADDR_IN *)ipv4->AddrArray[i].MaxSa;
239 ok( sa->sin_family == AF_INET, "got %d\n", sa->sin_family );
240 ok( sa->sin_addr.s_addr == ip4_array->AddrArray[i], "got %#lx vs %#lx\n",
241 sa->sin_addr.s_addr, ip4_array->AddrArray[i] );
242 ok( ipv4->AddrArray[i].Data.DnsAddrUserDword[0] == sizeof(*sa), "got %lu\n",
243 ipv4->AddrArray[i].Data.DnsAddrUserDword[0] );
246 size = 0;
247 err = DnsQueryConfig( DnsConfigDnsServersIpv6, 0, name, NULL, NULL, &size );
248 ok( !err || err == DNS_ERROR_NO_DNS_SERVERS, "got %ld\n", err );
249 ipv6_count = 0;
250 ipv6 = NULL;
251 if (!err)
253 ipv6 = malloc( size );
254 err = DnsQueryConfig( DnsConfigDnsServersIpv6, 0, name, NULL, ipv6, &size );
255 ok( !err, "got %ld\n", err );
256 ipv6_count = ipv6->AddrCount;
259 size = 0;
260 err = DnsQueryConfig( DnsConfigDnsServersUnspec, 0, name, NULL, NULL, &size );
261 ok( !err, "got %ld\n", err );
262 unspec = malloc( size );
263 err = DnsQueryConfig( DnsConfigDnsServersUnspec, 0, name, NULL, unspec, &size );
264 ok( !err, "got %ld\n", err );
266 ok( unspec->AddrCount == ipv4->AddrCount + ipv6_count, "got %lu vs %lu + %lu\n",
267 unspec->AddrCount, ipv4->AddrCount, ipv6_count );
269 free( ip4_array );
270 free( unspec );
271 free( ipv6 );
272 free( ipv4 );
275 free( adapters );
278 START_TEST(query)
280 WSADATA data;
282 WSAStartup(MAKEWORD(2, 2), &data);
284 test_DnsQuery();
285 test_DnsQueryConfig();