include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / dnsapi / tests / query.c
blobd2472f61f8812e67b301a2e3a19fc4283d5092f6
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 "ws2tcpip.h"
29 #include "iphlpapi.h"
31 #include "wine/test.h"
33 #define NS_MAXDNAME 1025
35 static void dump_dns_records(DNS_RECORDW *rec)
37 while (rec)
39 if (rec->wType == DNS_TYPE_CNAME)
40 printf(" %s type=CNAME -> %s\n", wine_dbgstr_w(rec->pName), wine_dbgstr_w(rec->Data.CNAME.pNameHost));
41 else if (rec->wType == DNS_TYPE_A)
43 char buf[16];
44 const char *addr;
45 addr = inet_ntop(AF_INET, &rec->Data.A.IpAddress, buf, sizeof(buf));
46 printf(" %s type=A -> %s\n", wine_dbgstr_w(rec->pName), addr ? addr : "(unknown IPv4 address)");
48 else if (rec->wType == DNS_TYPE_AAAA)
50 char buf[46];
51 const char *addr;
52 addr = inet_ntop(AF_INET6, &rec->Data.AAAA.Ip6Address, buf, sizeof(buf));
53 printf(" %s type=AAAA -> %s\n", wine_dbgstr_w(rec->pName), addr ? addr : "(unknown IPv6 address)");
55 else
56 printf(" %s type=%d\n", wine_dbgstr_w(rec->pName), rec->wType);
57 rec = rec->pNext;
61 static void test_DnsQuery(void)
63 WCHAR domain[MAX_PATH];
64 WCHAR name[NS_MAXDNAME];
65 DWORD ret, size;
66 DNS_RECORDW *rec, *ptr;
67 DNS_STATUS status;
69 /* IP in name. */
70 status = DnsQuery_W(L" 192.168.111.11", DNS_TYPE_A, 0, NULL, &rec, NULL);
71 ok(status != ERROR_SUCCESS, "got %lu.\n", status);
72 status = DnsQuery_W(L"192.168.111.11 ", DNS_TYPE_A, 0, NULL, &rec, NULL);
73 ok(status != ERROR_SUCCESS, "got %lu.\n", status);
75 status = DnsQuery_W(L"192.168.111.11", DNS_TYPE_A, 0, NULL, &rec, NULL);
76 ok(!status, "got %lu.\n", status);
77 ok(rec->wType == DNS_TYPE_A, "got %#x.\n", rec->wType);
78 ok(rec->wDataLength == sizeof(rec->Data.A), "got %u.\n", rec->wDataLength);
79 ok(rec->Data.A.IpAddress == 0x0b6fa8c0, "got %#lx.\n", rec->Data.A.IpAddress);
80 ok(!rec->pNext, "got %p.\n", rec->pNext);
81 ok(rec->dwTtl == 604800, "got %lu.\n", rec->dwTtl);
82 ok(!wcscmp(rec->pName, L"192.168.111.11"), "got %s.\n", debugstr_w(rec->pName));
83 ok(!rec->Flags.S.Section, "got %u.\n", rec->Flags.S.Section);
84 ok(!rec->Flags.S.Delete, "got %u.\n", rec->Flags.S.Delete);
85 ok(rec->Flags.S.CharSet == DnsCharSetUnicode, "got %u.\n", rec->Flags.S.CharSet);
86 ok(!rec->Flags.S.Unused, "got %u.\n", rec->Flags.S.Unused);
87 ok(rec->Flags.S.Reserved == 0x20, "got %u.\n", rec->Flags.S.Reserved);
88 DnsRecordListFree(rec, DnsFreeRecordList);
90 status = DnsQuery_W(L"2001:db8:3333:4444:5555:6666:7777:8888", DNS_TYPE_AAAA, 0, NULL, &rec, NULL);
91 ok(!status, "got %lu.\n", status);
92 ok(rec->wType == DNS_TYPE_AAAA, "got %#x.\n", rec->wType);
93 ok(rec->wDataLength == sizeof(rec->Data.AAAA), "got %u.\n", rec->wDataLength);
94 ok(rec->Data.AAAA.Ip6Address.IP6Dword[0] == 0xb80d0120, "got %#lx.\n", rec->Data.AAAA.Ip6Address.IP6Dword[0]);
95 ok(rec->Data.AAAA.Ip6Address.IP6Dword[1] == 0x44443333, "got %#lx.\n", rec->Data.AAAA.Ip6Address.IP6Dword[1]);
96 ok(rec->Data.AAAA.Ip6Address.IP6Dword[2] == 0x66665555, "got %#lx.\n", rec->Data.AAAA.Ip6Address.IP6Dword[2]);
97 ok(rec->Data.AAAA.Ip6Address.IP6Dword[3] == 0x88887777, "got %#lx.\n", rec->Data.AAAA.Ip6Address.IP6Dword[3]);
98 ok(!rec->pNext, "got %p.\n", rec->pNext);
99 ok(rec->dwTtl == 604800, "got %lu.\n", rec->dwTtl);
100 ok(!wcscmp(rec->pName, L"2001:db8:3333:4444:5555:6666:7777:8888"), "got %s.\n", debugstr_w(rec->pName));
101 ok(!rec->Flags.S.Section, "got %u.\n", rec->Flags.S.Section);
102 ok(!rec->Flags.S.Delete, "got %u.\n", rec->Flags.S.Delete);
103 ok(rec->Flags.S.CharSet == DnsCharSetUnicode, "got %u.\n", rec->Flags.S.CharSet);
104 ok(!rec->Flags.S.Unused, "got %u.\n", rec->Flags.S.Unused);
105 ok(rec->Flags.S.Reserved == 0x20, "got %u.\n", rec->Flags.S.Reserved);
106 DnsRecordListFree(rec, DnsFreeRecordList);
108 rec = NULL;
109 status = DnsQuery_W(L"winehq.org", DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &rec, NULL);
110 if (status == ERROR_TIMEOUT)
112 skip("query timed out\n");
113 return;
115 ok(status == ERROR_SUCCESS, "got %ld\n", status);
116 DnsRecordListFree(rec, DnsFreeRecordList);
118 /* Show that DNS_TYPE_A returns CNAMEs too */
119 rec = NULL;
120 wcscpy(domain, L"test.winehq.org"); /* should be a CNAME */
121 status = DnsQuery_W(domain, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &rec, NULL);
122 if (status == ERROR_TIMEOUT)
124 skip("query timed out\n");
125 return;
127 ok(status == ERROR_SUCCESS, "got %ld\n", status);
128 if (status == ERROR_SUCCESS && winetest_debug > 1)
130 trace("DnsQuery DNS_TYPE_A:\n");
131 dump_dns_records(rec);
134 ptr = rec; /* CNAMEs come first */
135 ok(!wcscmp(domain, ptr->pName), "expected record name %s, got %s\n", wine_dbgstr_w(domain), wine_dbgstr_w(ptr->pName));
136 ok(DNS_TYPE_CNAME == ptr->wType, "expected record type %d, got %d\n", DNS_TYPE_CNAME, ptr->wType);
137 wcscpy(domain, L"winehq.org");
138 if (ptr->wType == DNS_TYPE_CNAME)
139 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));
140 ptr = ptr->pNext;
142 ok(!wcscmp(domain, ptr->pName), "expected record name %s, got %s\n",
143 wine_dbgstr_w(domain), wine_dbgstr_w(ptr->pName));
144 ok(DNS_TYPE_A == ptr->wType, "expected record type %d, got %d\n",
145 DNS_TYPE_A, ptr->wType);
146 ptr = ptr->pNext;
148 while (ptr)
150 ok(wcscmp(domain, ptr->pName), "did not expect a record for %s\n",
151 wine_dbgstr_w(ptr->pName));
152 ok(ptr->wType == DNS_TYPE_A || ptr->wType == DNS_TYPE_AAAA || ptr->wType == DNS_TYPE_OPT,
153 "unexpected record type %d\n", ptr->wType);
154 ptr = ptr->pNext;
157 DnsRecordListFree(rec, DnsFreeRecordList);
159 /* DNS_TYPE_CNAME does not return a record for its target but it may still
160 * return other related records!
162 rec = NULL;
163 wcscpy(domain, L"test.winehq.org");
164 status = DnsQuery_W(L"test.winehq.org", DNS_TYPE_CNAME, DNS_QUERY_STANDARD, NULL, &rec, NULL);
165 if (status == ERROR_TIMEOUT)
167 skip("query timed out\n");
168 return;
170 if (status == DNS_INFO_NO_RECORDS)
172 skip("no CNAME records\n");
173 return;
175 ok(status == ERROR_SUCCESS, "got %ld\n", status);
176 if (status == ERROR_SUCCESS && winetest_debug > 1)
178 trace("DnsQuery DNS_TYPE_CNAME:\n");
179 dump_dns_records(rec);
182 ptr = rec;
183 ok(!wcscmp(domain, ptr->pName), "expected record name %s, got %s\n", wine_dbgstr_w(domain), wine_dbgstr_w(ptr->pName));
184 ok(DNS_TYPE_CNAME == ptr->wType, "expected record type %d, got %d\n", DNS_TYPE_CNAME, ptr->wType);
185 wcscpy(domain, L"winehq.org");
186 if (ptr->wType == DNS_TYPE_CNAME)
187 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));
188 DnsRecordListFree(rec, DnsFreeRecordList);
190 status = DnsQuery_W(L"", DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
191 ok(status == DNS_ERROR_RCODE_NAME_ERROR || status == DNS_INFO_NO_RECORDS || status == ERROR_INVALID_NAME /* XP */,
192 "got %ld\n", status);
194 wcscpy(domain, L"_ldap._tcp.deadbeef");
195 status = DnsQuery_W(domain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
196 ok(status == DNS_ERROR_RCODE_NAME_ERROR || status == DNS_INFO_NO_RECORDS || status == ERROR_INVALID_NAME /* XP */,
197 "got %ld\n", status);
199 wcscpy(domain, L"_ldap._tcp.dc._msdcs.");
200 size = ARRAY_SIZE(domain) - wcslen(domain);
201 ret = GetComputerNameExW(ComputerNameDnsDomain, domain + wcslen(domain), &size);
202 ok(ret, "GetComputerNameEx error %lu\n", GetLastError());
203 if (!size)
205 skip("computer is not in a domain\n");
206 return;
209 status = DnsQuery_W(domain, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
210 trace("DnsQuery_W(%s) => %ld\n", wine_dbgstr_w(domain), status);
211 if (status != ERROR_SUCCESS)
213 skip("domain %s doesn't have an SRV entry\n", wine_dbgstr_w(domain));
214 return;
217 trace("target %s, port %d\n", wine_dbgstr_w(rec->Data.Srv.pNameTarget), rec->Data.Srv.wPort);
219 lstrcpynW(name, rec->Data.Srv.pNameTarget, ARRAY_SIZE(name));
220 DnsRecordListFree(rec, DnsFreeRecordList);
222 /* IPv4 */
223 status = DnsQuery_W(name, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &rec, NULL);
224 ok(status == ERROR_SUCCESS || status == DNS_ERROR_RCODE_NAME_ERROR, "DnsQuery_W(%s) => %ld\n",
225 wine_dbgstr_w(name), status);
226 if (status == ERROR_SUCCESS)
228 SOCKADDR_IN addr;
229 WCHAR buf[IP4_ADDRESS_STRING_LENGTH];
231 addr.sin_family = AF_INET;
232 addr.sin_port = 0;
233 addr.sin_addr.s_addr = rec->Data.A.IpAddress;
234 size = sizeof(buf);
235 ret = WSAAddressToStringW((SOCKADDR *)&addr, sizeof(addr), NULL, buf, &size);
236 ok(!ret, "WSAAddressToStringW error %lu\n", ret);
237 trace("WSAAddressToStringW => %s\n", wine_dbgstr_w(buf));
239 DnsRecordListFree(rec, DnsFreeRecordList);
242 /* IPv6 */
243 status = DnsQuery_W(name, DNS_TYPE_AAAA, DNS_QUERY_STANDARD, NULL, &rec, NULL);
244 ok(status == ERROR_SUCCESS || status == DNS_ERROR_RCODE_NAME_ERROR, "DnsQuery_W(%s) => %ld\n",
245 wine_dbgstr_w(name), status);
246 if (status == ERROR_SUCCESS)
248 SOCKADDR_IN6 addr;
249 WCHAR buf[IP6_ADDRESS_STRING_LENGTH];
251 addr.sin6_family = AF_INET6;
252 addr.sin6_port = 0;
253 addr.sin6_scope_id = 0;
254 memcpy(addr.sin6_addr.s6_addr, &rec->Data.AAAA.Ip6Address, sizeof(rec->Data.AAAA.Ip6Address));
255 size = sizeof(buf);
256 ret = WSAAddressToStringW((SOCKADDR *)&addr, sizeof(addr), NULL, buf, &size);
257 ok(!ret, "WSAAddressToStringW error %lu\n", ret);
258 trace("WSAAddressToStringW => %s\n", wine_dbgstr_w(buf));
260 DnsRecordListFree(rec, DnsFreeRecordList);
264 static IP_ADAPTER_ADDRESSES *get_adapters(void)
266 ULONG err, size = 1024;
267 IP_ADAPTER_ADDRESSES *ret = malloc( size );
268 for (;;)
270 err = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
271 GAA_FLAG_SKIP_FRIENDLY_NAME,
272 NULL, ret, &size );
273 if (err != ERROR_BUFFER_OVERFLOW) break;
274 ret = realloc( ret, size );
276 if (err == ERROR_SUCCESS) return ret;
277 free( ret );
278 return NULL;
281 static void test_DnsQueryConfig( void )
283 DNS_STATUS err;
284 DWORD size, i, ipv6_count;
285 WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1];
286 IP_ADAPTER_ADDRESSES *adapters, *ptr;
287 DNS_ADDR_ARRAY *ipv4, *ipv6, *unspec;
288 IP4_ARRAY *ip4_array;
290 if (!(adapters = get_adapters())) return;
292 for (ptr = adapters; ptr; ptr = ptr->Next)
294 MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
295 if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
297 size = 0;
298 err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, NULL, &size );
299 if (err) continue;
300 ipv4 = malloc( size );
301 size--;
302 err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, ipv4, &size );
303 ok( err == ERROR_MORE_DATA, "got %ld\n", err );
304 size++;
305 err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, ipv4, &size );
306 ok( !err, "got %ld\n", err );
308 ok( ipv4->AddrCount == ipv4->MaxCount, "got %lu vs %lu\n", ipv4->AddrCount, ipv4->MaxCount );
309 ok( !ipv4->Tag, "got %#lx\n", ipv4->Tag );
310 ok( !ipv4->Family, "got %d\n", ipv4->Family );
311 ok( !ipv4->WordReserved, "got %#x\n", ipv4->WordReserved );
312 ok( !ipv4->Flags, "got %#lx\n", ipv4->Flags );
313 ok( !ipv4->MatchFlag, "got %#lx\n", ipv4->MatchFlag );
314 ok( !ipv4->Reserved1, "got %#lx\n", ipv4->Reserved1 );
315 ok( !ipv4->Reserved2, "got %#lx\n", ipv4->Reserved2 );
317 size = 0;
318 err = DnsQueryConfig( DnsConfigDnsServerList, 0, name, NULL, NULL, &size );
319 ok( !err, "got %ld\n", err );
320 ip4_array = malloc( size );
321 err = DnsQueryConfig( DnsConfigDnsServerList, 0, name, NULL, ip4_array, &size );
322 ok( !err, "got %ld\n", err );
324 ok( ipv4->AddrCount == ip4_array->AddrCount, "got %lu vs %lu\n", ipv4->AddrCount, ip4_array->AddrCount );
326 for (i = 0; i < ipv4->AddrCount; i++)
328 SOCKADDR_IN *sa = (SOCKADDR_IN *)ipv4->AddrArray[i].MaxSa;
330 ok( sa->sin_family == AF_INET, "got %d\n", sa->sin_family );
331 ok( sa->sin_addr.s_addr == ip4_array->AddrArray[i], "got %#lx vs %#lx\n",
332 sa->sin_addr.s_addr, ip4_array->AddrArray[i] );
333 ok( ipv4->AddrArray[i].Data.DnsAddrUserDword[0] == sizeof(*sa), "got %lu\n",
334 ipv4->AddrArray[i].Data.DnsAddrUserDword[0] );
337 size = 0;
338 err = DnsQueryConfig( DnsConfigDnsServersIpv6, 0, name, NULL, NULL, &size );
339 ok( !err || err == DNS_ERROR_NO_DNS_SERVERS, "got %ld\n", err );
340 ipv6_count = 0;
341 ipv6 = NULL;
342 if (!err)
344 ipv6 = malloc( size );
345 err = DnsQueryConfig( DnsConfigDnsServersIpv6, 0, name, NULL, ipv6, &size );
346 ok( !err, "got %ld\n", err );
347 ipv6_count = ipv6->AddrCount;
350 size = 0;
351 err = DnsQueryConfig( DnsConfigDnsServersUnspec, 0, name, NULL, NULL, &size );
352 ok( !err, "got %ld\n", err );
353 unspec = malloc( size );
354 err = DnsQueryConfig( DnsConfigDnsServersUnspec, 0, name, NULL, unspec, &size );
355 ok( !err, "got %ld\n", err );
357 ok( unspec->AddrCount == ipv4->AddrCount + ipv6_count, "got %lu vs %lu + %lu\n",
358 unspec->AddrCount, ipv4->AddrCount, ipv6_count );
360 free( ip4_array );
361 free( unspec );
362 free( ipv6 );
363 free( ipv4 );
366 free( adapters );
369 START_TEST(query)
371 WSADATA data;
373 WSAStartup(MAKEWORD(2, 2), &data);
375 test_DnsQuery();
376 test_DnsQueryConfig();