38f25d39b4bda4ffd66c9040e338c8996ae04488
[reactos.git] / reactos / dll / win32 / dnsapi / dnsapi / query.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/dnsapi/dnsapi/query.c
5 * PURPOSE: DNSAPI functions built on the ADNS library.
6 * PROGRAMER: Art Yerkes
7 * UPDATE HISTORY:
8 * 12/15/03 -- Created
9 */
10
11 #include "precomp.h"
12 #include <winreg.h>
13 #include <iphlpapi.h>
14 #include <strsafe.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* DnsQuery ****************************
20 * Begin a DNS query, and allow the result to be placed in the application
21 * supplied result pointer. The result can be manipulated with the record
22 * functions.
23 *
24 * Name -- The DNS object to be queried.
25 * Type -- The type of records to be returned. These are
26 * listed in windns.h
27 * Options -- Query options. DNS_QUERY_STANDARD is the base
28 * state, and every other option takes precedence.
29 * multiple options can be combined. Listed in
30 * windns.h
31 * Servers -- List of alternate servers (optional)
32 * QueryResultSet -- Pointer to the result pointer that will be filled
33 * when the response is available.
34 * Reserved -- Response as it appears on the wire. Optional.
35 */
36
37 static PCHAR
38 DnsWToC(const WCHAR *WideString)
39 {
40 PCHAR AnsiString;
41 int AnsiLen = WideCharToMultiByte(CP_ACP,
42 0,
43 WideString,
44 -1,
45 NULL,
46 0,
47 NULL,
48 0);
49 if (AnsiLen == 0)
50 return NULL;
51 AnsiString = RtlAllocateHeap(RtlGetProcessHeap(), 0, AnsiLen);
52 if (AnsiString == NULL)
53 {
54 return NULL;
55 }
56 WideCharToMultiByte(CP_ACP,
57 0,
58 WideString,
59 -1,
60 AnsiString,
61 AnsiLen,
62 NULL,
63 0);
64
65 return AnsiString;
66 }
67
68 static PWCHAR
69 DnsCToW(const CHAR *NarrowString)
70 {
71 PWCHAR WideString;
72 int WideLen = MultiByteToWideChar(CP_ACP,
73 0,
74 NarrowString,
75 -1,
76 NULL,
77 0);
78 if (WideLen == 0)
79 return NULL;
80 WideLen *= sizeof(WCHAR);
81 WideString = RtlAllocateHeap(RtlGetProcessHeap(), 0, WideLen);
82 if (WideString == NULL)
83 {
84 return NULL;
85 }
86 MultiByteToWideChar(CP_ACP,
87 0,
88 NarrowString,
89 -1,
90 WideString,
91 WideLen);
92
93 return WideString;
94 }
95
96 DNS_STATUS WINAPI
97 DnsQuery_A(LPCSTR Name,
98 WORD Type,
99 DWORD Options,
100 PIP4_ARRAY Servers,
101 PDNS_RECORD *QueryResultSet,
102 PVOID *Reserved)
103 {
104 UINT i;
105 PWCHAR Buffer;
106 DNS_STATUS Status;
107 PDNS_RECORD QueryResultWide;
108 PDNS_RECORD ConvertedRecord = 0, LastRecord = 0;
109
110 if (Name == NULL)
111 return ERROR_INVALID_PARAMETER;
112 if (QueryResultSet == NULL)
113 return ERROR_INVALID_PARAMETER;
114
115 Buffer = DnsCToW(Name);
116
117 Status = DnsQuery_W(Buffer, Type, Options, Servers, &QueryResultWide, Reserved);
118
119 while (Status == ERROR_SUCCESS && QueryResultWide)
120 {
121 switch (QueryResultWide->wType)
122 {
123 case DNS_TYPE_A:
124 case DNS_TYPE_WKS:
125 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
126 ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
127 ConvertedRecord->wType = QueryResultWide->wType;
128 ConvertedRecord->wDataLength = QueryResultWide->wDataLength;
129 memcpy(&ConvertedRecord->Data, &QueryResultWide->Data, QueryResultWide->wDataLength);
130 break;
131
132 case DNS_TYPE_CNAME:
133 case DNS_TYPE_PTR:
134 case DNS_TYPE_NS:
135 case DNS_TYPE_MB:
136 case DNS_TYPE_MD:
137 case DNS_TYPE_MF:
138 case DNS_TYPE_MG:
139 case DNS_TYPE_MR:
140 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
141 ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
142 ConvertedRecord->wType = QueryResultWide->wType;
143 ConvertedRecord->wDataLength = sizeof(DNS_PTR_DATA);
144 ConvertedRecord->Data.PTR.pNameHost = DnsWToC((PWCHAR)QueryResultWide->Data.PTR.pNameHost);
145 break;
146
147 case DNS_TYPE_MINFO:
148 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
149 ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
150 ConvertedRecord->wType = QueryResultWide->wType;
151 ConvertedRecord->wDataLength = sizeof(DNS_MINFO_DATA);
152 ConvertedRecord->Data.MINFO.pNameMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameMailbox);
153 ConvertedRecord->Data.MINFO.pNameErrorsMailbox = DnsWToC((PWCHAR)QueryResultWide->Data.MINFO.pNameErrorsMailbox);
154 break;
155
156 case DNS_TYPE_MX:
157 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
158 ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
159 ConvertedRecord->wType = QueryResultWide->wType;
160 ConvertedRecord->wDataLength = sizeof(DNS_MX_DATA);
161 ConvertedRecord->Data.MX.pNameExchange = DnsWToC((PWCHAR)QueryResultWide->Data.MX.pNameExchange);
162 ConvertedRecord->Data.MX.wPreference = QueryResultWide->Data.MX.wPreference;
163 break;
164
165 case DNS_TYPE_HINFO:
166 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_TXT_DATA) + QueryResultWide->Data.TXT.dwStringCount);
167 ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
168 ConvertedRecord->wType = QueryResultWide->wType;
169 ConvertedRecord->wDataLength = sizeof(DNS_TXT_DATA) + (sizeof(PCHAR) * QueryResultWide->Data.TXT.dwStringCount);
170 ConvertedRecord->Data.TXT.dwStringCount = QueryResultWide->Data.TXT.dwStringCount;
171
172 for (i = 0; i < ConvertedRecord->Data.TXT.dwStringCount; i++)
173 ConvertedRecord->Data.TXT.pStringArray[i] = DnsWToC((PWCHAR)QueryResultWide->Data.TXT.pStringArray[i]);
174
175 break;
176
177 case DNS_TYPE_NULL:
178 ConvertedRecord = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount);
179 ConvertedRecord->pName = DnsWToC((PWCHAR)QueryResultWide->pName);
180 ConvertedRecord->wType = QueryResultWide->wType;
181 ConvertedRecord->wDataLength = sizeof(DNS_NULL_DATA) + QueryResultWide->Data.Null.dwByteCount;
182 ConvertedRecord->Data.Null.dwByteCount = QueryResultWide->Data.Null.dwByteCount;
183 memcpy(&ConvertedRecord->Data.Null.Data, &QueryResultWide->Data.Null.Data, QueryResultWide->Data.Null.dwByteCount);
184 break;
185 }
186
187 if (LastRecord)
188 {
189 LastRecord->pNext = ConvertedRecord;
190 LastRecord = LastRecord->pNext;
191 }
192 else
193 {
194 LastRecord = *QueryResultSet = ConvertedRecord;
195 }
196
197 QueryResultWide = QueryResultWide->pNext;
198 }
199
200 if (LastRecord)
201 LastRecord->pNext = 0;
202
203 /* The name */
204 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
205 /* The result*/
206 if (QueryResultWide) DnsIntFreeRecordList(QueryResultWide);
207
208 return Status;
209 }
210
211 WCHAR
212 *xstrsave(const WCHAR *str)
213 {
214 WCHAR *p;
215 size_t len = 0;
216
217 /* FIXME: how much instead of MAX_PATH? */
218 StringCbLengthW(str, MAX_PATH, &len);
219 len+=sizeof(WCHAR);
220
221 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
222
223 if (p)
224 StringCbCopyW(p, len, str);
225
226 return p;
227 }
228
229 CHAR
230 *xstrsaveA(const CHAR *str)
231 {
232 CHAR *p;
233 size_t len = 0;
234
235 /* FIXME: how much instead of MAX_PATH? */
236 StringCbLengthA(str, MAX_PATH, &len);
237 len++;
238
239 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, len);
240
241 if (p)
242 StringCbCopyA(p, len, str);
243
244 return p;
245 }
246
247 HANDLE
248 OpenNetworkDatabase(LPCWSTR Name)
249 {
250 PWSTR ExpandedPath;
251 PWSTR DatabasePath;
252 INT ErrorCode;
253 HKEY DatabaseKey;
254 DWORD RegType;
255 DWORD RegSize = 0;
256 size_t StringLength;
257 HANDLE ret;
258
259 ExpandedPath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
260 if (!ExpandedPath)
261 return INVALID_HANDLE_VALUE;
262
263 /* Open the database path key */
264 ErrorCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
265 L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
266 0,
267 KEY_READ,
268 &DatabaseKey);
269 if (ErrorCode == NO_ERROR)
270 {
271 /* Read the actual path */
272 ErrorCode = RegQueryValueExW(DatabaseKey,
273 L"DatabasePath",
274 NULL,
275 &RegType,
276 NULL,
277 &RegSize);
278
279 DatabasePath = HeapAlloc(GetProcessHeap(), 0, RegSize);
280 if (!DatabasePath)
281 {
282 HeapFree(GetProcessHeap(), 0, ExpandedPath);
283 return INVALID_HANDLE_VALUE;
284 }
285
286 /* Read the actual path */
287 ErrorCode = RegQueryValueExW(DatabaseKey,
288 L"DatabasePath",
289 NULL,
290 &RegType,
291 (LPBYTE)DatabasePath,
292 &RegSize);
293
294 /* Close the key */
295 RegCloseKey(DatabaseKey);
296
297 /* Expand the name */
298 ExpandEnvironmentStringsW(DatabasePath, ExpandedPath, MAX_PATH);
299
300 HeapFree(GetProcessHeap(), 0, DatabasePath);
301 }
302 else
303 {
304 /* Use defalt path */
305 GetSystemDirectoryW(ExpandedPath, MAX_PATH);
306 StringCchLengthW(ExpandedPath, MAX_PATH, &StringLength);
307 if (ExpandedPath[StringLength - 1] != L'\\')
308 {
309 /* It isn't, so add it ourselves */
310 StringCchCatW(ExpandedPath, MAX_PATH, L"\\");
311 }
312 StringCchCatW(ExpandedPath, MAX_PATH, L"DRIVERS\\ETC\\");
313 }
314
315 /* Make sure that the path is backslash-terminated */
316 StringCchLengthW(ExpandedPath, MAX_PATH, &StringLength);
317 if (ExpandedPath[StringLength - 1] != L'\\')
318 {
319 /* It isn't, so add it ourselves */
320 StringCchCatW(ExpandedPath, MAX_PATH, L"\\");
321 }
322
323 /* Add the database name */
324 StringCchCatW(ExpandedPath, MAX_PATH, Name);
325
326 /* Return a handle to the file */
327 ret = CreateFileW(ExpandedPath,
328 FILE_READ_DATA,
329 FILE_SHARE_READ,
330 NULL,
331 OPEN_EXISTING,
332 FILE_ATTRIBUTE_NORMAL,
333 NULL);
334
335 HeapFree(GetProcessHeap(), 0, ExpandedPath);
336 return ret;
337 }
338
339 /* This function is far from perfect but it works enough */
340 IP4_ADDRESS
341 CheckForCurrentHostname(CONST CHAR * Name, PFIXED_INFO network_info)
342 {
343 PCHAR TempName;
344 DWORD AdapterAddressesSize, Status;
345 IP4_ADDRESS ret = 0, Address;
346 PIP_ADAPTER_ADDRESSES Addresses = NULL, pip;
347 BOOL Found = FALSE;
348
349 if (network_info->DomainName[0])
350 {
351 size_t StringLength;
352 size_t TempSize = 2;
353 StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
354 TempSize += StringLength;
355 StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
356 TempSize += StringLength;
357 TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, TempSize);
358 StringCchCopyA(TempName, TempSize, network_info->HostName);
359 StringCchCatA(TempName, TempSize, ".");
360 StringCchCatA(TempName, TempSize, network_info->DomainName);
361 }
362 else
363 {
364 TempName = RtlAllocateHeap(RtlGetProcessHeap(), 0, 1);
365 TempName[0] = 0;
366 }
367 Found = !stricmp(Name, network_info->HostName) || !stricmp(Name, TempName);
368 RtlFreeHeap(RtlGetProcessHeap(), 0, TempName);
369 if (!Found)
370 {
371 return 0;
372 }
373 /* get adapter info */
374 AdapterAddressesSize = 0;
375 GetAdaptersAddresses(AF_INET,
376 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
377 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
378 NULL,
379 Addresses,
380 &AdapterAddressesSize);
381 if (!AdapterAddressesSize)
382 {
383 return 0;
384 }
385 Addresses = RtlAllocateHeap(RtlGetProcessHeap(), 0, AdapterAddressesSize);
386 Status = GetAdaptersAddresses(AF_INET,
387 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER |
388 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST,
389 NULL,
390 Addresses,
391 &AdapterAddressesSize);
392 if (Status)
393 {
394 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
395 return 0;
396 }
397 for (pip = Addresses; pip != NULL; pip = pip->Next) {
398 Address = ((LPSOCKADDR_IN)pip->FirstUnicastAddress->Address.lpSockaddr)->sin_addr.S_un.S_addr;
399 if (Address != ntohl(INADDR_LOOPBACK))
400 break;
401 }
402 if (Address && Address != ntohl(INADDR_LOOPBACK))
403 {
404 ret = Address;
405 }
406 RtlFreeHeap(RtlGetProcessHeap(), 0, Addresses);
407 return ret;
408 }
409
410 BOOL
411 ParseV4Address(LPCSTR AddressString,
412 OUT PDWORD pAddress)
413 {
414 CHAR * cp = (CHAR *)AddressString;
415 DWORD val, base;
416 unsigned char c;
417 DWORD parts[4], *pp = parts;
418 if (!AddressString)
419 return FALSE;
420 if (!isdigit(*cp)) return FALSE;
421
422 again:
423 /*
424 * Collect number up to ``.''.
425 * Values are specified as for C:
426 * 0x=hex, 0=octal, other=decimal.
427 */
428 val = 0; base = 10;
429 if (*cp == '0') {
430 if (*++cp == 'x' || *cp == 'X')
431 base = 16, cp++;
432 else
433 base = 8;
434 }
435 while ((c = *cp)) {
436 if (isdigit(c)) {
437 val = (val * base) + (c - '0');
438 cp++;
439 continue;
440 }
441 if (base == 16 && isxdigit(c)) {
442 val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
443 cp++;
444 continue;
445 }
446 break;
447 }
448 if (*cp == '.') {
449 /*
450 * Internet format:
451 * a.b.c.d
452 */
453 if (pp >= parts + 4) return FALSE;
454 *pp++ = val;
455 cp++;
456 goto again;
457 }
458 /*
459 * Check for trailing characters.
460 */
461 if (*cp && *cp > ' ') return FALSE;
462
463 *pp++ = val;
464 /*
465 * Concoct the address according to
466 * the number of parts specified.
467 */
468 if ((DWORD)(pp - parts) != 4) return FALSE;
469 if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return FALSE;
470 val = (parts[3] << 24) | (parts[2] << 16) | (parts[1] << 8) | parts[0];
471
472 if (pAddress)
473 *pAddress = val;
474
475 return TRUE;
476 }
477
478 /* This function is far from perfect but it works enough */
479 IP4_ADDRESS
480 FindEntryInHosts(CONST CHAR * name)
481 {
482 BOOL Found = FALSE;
483 HANDLE HostsFile;
484 CHAR HostsDBData[BUFSIZ] = { 0 };
485 PCHAR AddressStr, DnsName = NULL, AddrTerm, NameSt, NextLine, ThisLine, Comment;
486 UINT ValidData = 0;
487 DWORD ReadSize;
488 DWORD Address;
489
490 /* Open the network database */
491 HostsFile = OpenNetworkDatabase(L"hosts");
492 if (HostsFile == INVALID_HANDLE_VALUE)
493 {
494 WSASetLastError(WSANO_RECOVERY);
495 return 0;
496 }
497
498 while (!Found && ReadFile(HostsFile,
499 HostsDBData + ValidData,
500 sizeof(HostsDBData) - ValidData,
501 &ReadSize,
502 NULL))
503 {
504 ValidData += ReadSize;
505 ReadSize = 0;
506 NextLine = ThisLine = HostsDBData;
507
508 /* Find the beginning of the next line */
509 while ((NextLine < HostsDBData + ValidData) &&
510 (*NextLine != '\r') &&
511 (*NextLine != '\n'))
512 {
513 NextLine++;
514 }
515
516 /* Zero and skip, so we can treat what we have as a string */
517 if (NextLine > HostsDBData + ValidData)
518 break;
519
520 *NextLine = 0;
521 NextLine++;
522
523 Comment = strchr(ThisLine, '#');
524 if (Comment)
525 *Comment = 0; /* Terminate at comment start */
526
527 AddressStr = ThisLine;
528 /* Find the first space separating the IP address from the DNS name */
529 AddrTerm = strchr(ThisLine, ' ');
530 if (AddrTerm)
531 {
532 /* Terminate the address string */
533 *AddrTerm = 0;
534
535 /* Find the last space before the DNS name */
536 NameSt = strrchr(ThisLine, ' ');
537
538 /* If there is only one space (the one we removed above), then just use the address terminator */
539 if (!NameSt)
540 NameSt = AddrTerm;
541
542 /* Move from the space to the first character of the DNS name */
543 NameSt++;
544
545 DnsName = NameSt;
546
547 if (!stricmp(name, DnsName) || !stricmp(name, AddressStr))
548 {
549 Found = TRUE;
550 break;
551 }
552 }
553
554 /* Get rid of everything we read so far */
555 while (NextLine <= HostsDBData + ValidData &&
556 isspace(*NextLine))
557 {
558 NextLine++;
559 }
560
561 if (HostsDBData + ValidData - NextLine <= 0)
562 break;
563
564 memmove(HostsDBData, NextLine, HostsDBData + ValidData - NextLine);
565 ValidData -= NextLine - HostsDBData;
566 }
567
568 CloseHandle(HostsFile);
569
570 if (!Found)
571 {
572 WSASetLastError(WSANO_DATA);
573 return 0;
574 }
575
576 if (strstr(AddressStr, ":"))
577 {
578 WSASetLastError(WSAEINVAL);
579 return 0;
580 }
581
582 if (!ParseV4Address(AddressStr, &Address))
583 {
584 WSASetLastError(WSAEINVAL);
585 return 0;
586 }
587
588 return Address;
589 }
590
591 DNS_STATUS WINAPI
592 DnsQuery_W(LPCWSTR Name,
593 WORD Type,
594 DWORD Options,
595 PIP4_ARRAY Servers,
596 PDNS_RECORD *QueryResultSet,
597 PVOID *Reserved)
598 {
599 adns_state astate;
600 int quflags = (Options & DNS_QUERY_NO_RECURSION) == 0 ? adns_qf_search : 0;
601 int adns_error;
602 adns_answer *answer;
603 LPSTR CurrentName;
604 unsigned i, CNameLoop;
605 PFIXED_INFO network_info;
606 ULONG network_info_blen = 0;
607 DWORD network_info_result;
608 PIP_ADDR_STRING pip;
609 IP4_ADDRESS Address;
610 struct in_addr addr;
611 PCHAR HostWithDomainName;
612 PCHAR AnsiName;
613 size_t NameLen = 0;
614
615 if (Name == NULL)
616 return ERROR_INVALID_PARAMETER;
617 if (QueryResultSet == NULL)
618 return ERROR_INVALID_PARAMETER;
619 if ((Options & DNS_QUERY_WIRE_ONLY) != 0 && (Options & DNS_QUERY_NO_WIRE_QUERY) != 0)
620 return ERROR_INVALID_PARAMETER;
621
622 *QueryResultSet = 0;
623
624 switch (Type)
625 {
626 case DNS_TYPE_A:
627 /* FIXME: how much instead of MAX_PATH? */
628 NameLen = WideCharToMultiByte(CP_ACP,
629 0,
630 Name,
631 -1,
632 NULL,
633 0,
634 NULL,
635 0);
636 AnsiName = RtlAllocateHeap(RtlGetProcessHeap(), 0, NameLen);
637 if (NULL == AnsiName)
638 {
639 return ERROR_OUTOFMEMORY;
640 }
641 WideCharToMultiByte(CP_ACP,
642 0,
643 Name,
644 -1,
645 AnsiName,
646 NameLen,
647 NULL,
648 0);
649 NameLen--;
650 /* Is it an IPv4 address? */
651 if (ParseV4Address(AnsiName, &Address))
652 {
653 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
654 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
655
656 if (NULL == *QueryResultSet)
657 {
658 return ERROR_OUTOFMEMORY;
659 }
660
661 (*QueryResultSet)->pNext = NULL;
662 (*QueryResultSet)->wType = Type;
663 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
664 (*QueryResultSet)->Data.A.IpAddress = Address;
665
666 (*QueryResultSet)->pName = (LPSTR)xstrsave(Name);
667
668 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
669 }
670
671 /* Check allowed characters
672 * According to RFC a-z,A-Z,0-9,-,_, but can't start or end with - or _
673 */
674 if (AnsiName[0] == '-' || AnsiName[0] == '_' || AnsiName[NameLen - 1] == '-' ||
675 AnsiName[NameLen - 1] == '_' || strstr(AnsiName, "..") != NULL)
676 {
677 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
678 return ERROR_INVALID_NAME;
679 }
680 i = 0;
681 while (i < NameLen)
682 {
683 if (!((AnsiName[i] >= 'a' && AnsiName[i] <= 'z') ||
684 (AnsiName[i] >= 'A' && AnsiName[i] <= 'Z') ||
685 (AnsiName[i] >= '0' && AnsiName[i] <= '9') ||
686 AnsiName[i] == '-' || AnsiName[i] == '_' || AnsiName[i] == '.'))
687 {
688 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
689 return ERROR_INVALID_NAME;
690 }
691 i++;
692 }
693
694 if ((Options & DNS_QUERY_NO_HOSTS_FILE) == 0)
695 {
696 if ((Address = FindEntryInHosts(AnsiName)) != 0)
697 {
698 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
699 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
700
701 if (NULL == *QueryResultSet)
702 {
703 return ERROR_OUTOFMEMORY;
704 }
705
706 (*QueryResultSet)->pNext = NULL;
707 (*QueryResultSet)->wType = Type;
708 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
709 (*QueryResultSet)->Data.A.IpAddress = Address;
710
711 (*QueryResultSet)->pName = (LPSTR)xstrsave(Name);
712
713 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
714 }
715 }
716
717 network_info_result = GetNetworkParams(NULL, &network_info_blen);
718 network_info = (PFIXED_INFO)RtlAllocateHeap(RtlGetProcessHeap(), 0, (size_t)network_info_blen);
719 if (NULL == network_info)
720 {
721 return ERROR_OUTOFMEMORY;
722 }
723
724 network_info_result = GetNetworkParams(network_info, &network_info_blen);
725 if (network_info_result != ERROR_SUCCESS)
726 {
727 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
728 return network_info_result;
729 }
730
731 if ((Address = CheckForCurrentHostname(NameLen != 0 ? AnsiName : network_info->HostName, network_info)) != 0)
732 {
733 size_t TempLen = 2, StringLength = 0;
734 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
735 StringCchLengthA(network_info->HostName, sizeof(network_info->HostName), &StringLength);
736 TempLen += StringLength;
737 StringCchLengthA(network_info->DomainName, sizeof(network_info->DomainName), &StringLength);
738 TempLen += StringLength;
739 HostWithDomainName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), 0, TempLen);
740 StringCchCopyA(HostWithDomainName, TempLen, network_info->HostName);
741 if (network_info->DomainName[0])
742 {
743 StringCchCatA(HostWithDomainName, TempLen, ".");
744 StringCchCatA(HostWithDomainName, TempLen, network_info->DomainName);
745 }
746 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
747 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
748
749 if (NULL == *QueryResultSet)
750 {
751 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
752 return ERROR_OUTOFMEMORY;
753 }
754
755 (*QueryResultSet)->pNext = NULL;
756 (*QueryResultSet)->wType = Type;
757 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
758 (*QueryResultSet)->Data.A.IpAddress = Address;
759
760 (*QueryResultSet)->pName = (LPSTR)DnsCToW(HostWithDomainName);
761
762 RtlFreeHeap(RtlGetProcessHeap(), 0, HostWithDomainName);
763 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
764 }
765
766 if ((Options & DNS_QUERY_NO_WIRE_QUERY) != 0)
767 {
768 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
769 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
770 return ERROR_FILE_NOT_FOUND;
771 }
772
773 adns_error = adns_init(&astate, adns_if_noenv | adns_if_noerrprint | adns_if_noserverwarn, 0);
774 if (adns_error != adns_s_ok)
775 {
776 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
777 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
778 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
779 }
780 for (pip = &(network_info->DnsServerList); pip; pip = pip->Next)
781 {
782 addr.s_addr = inet_addr(pip->IpAddress.String);
783 if ((addr.s_addr != INADDR_ANY) && (addr.s_addr != INADDR_NONE))
784 adns_addserver(astate, addr);
785 }
786 if (network_info->DomainName[0])
787 {
788 adns_ccf_search(astate, "LOCALDOMAIN", -1, network_info->DomainName);
789 }
790 RtlFreeHeap(RtlGetProcessHeap(), 0, network_info);
791
792 if (Servers)
793 {
794 for (i = 0; i < Servers->AddrCount; i++)
795 {
796 adns_addserver(astate, *((struct in_addr *)&Servers->AddrArray[i]));
797 }
798 }
799
800 /*
801 * adns doesn't resolve chained CNAME records (a CNAME which points to
802 * another CNAME pointing to another... pointing to an A record), according
803 * to a mailing list thread the authors believe that chained CNAME records
804 * are invalid and the DNS entries should be fixed. That's a nice academic
805 * standpoint, but there certainly are chained CNAME records out there,
806 * even some fairly major ones (at the time of this writing
807 * download.mozilla.org is a chained CNAME). Everyone else seems to resolve
808 * these fine, so we should too. So we loop here to try to resolve CNAME
809 * chains ourselves. Of course, there must be a limit to protect against
810 * CNAME loops.
811 */
812
813 #define CNAME_LOOP_MAX 16
814
815 CurrentName = AnsiName;
816
817 for (CNameLoop = 0; CNameLoop < CNAME_LOOP_MAX; CNameLoop++)
818 {
819 adns_error = adns_synchronous(astate, CurrentName, adns_r_addr, quflags, &answer);
820
821 if (adns_error != adns_s_ok)
822 {
823 adns_finish(astate);
824
825 if (CurrentName != AnsiName)
826 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
827
828 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
829 return DnsIntTranslateAdnsToDNS_STATUS(adns_error);
830 }
831
832 if (answer && answer->rrs.addr)
833 {
834 if (CurrentName != AnsiName)
835 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
836
837 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
838 *QueryResultSet = (PDNS_RECORD)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(DNS_RECORD));
839
840 if (NULL == *QueryResultSet)
841 {
842 adns_finish(astate);
843 return ERROR_OUTOFMEMORY;
844 }
845
846 (*QueryResultSet)->pNext = NULL;
847 (*QueryResultSet)->wType = Type;
848 (*QueryResultSet)->wDataLength = sizeof(DNS_A_DATA);
849 (*QueryResultSet)->Data.A.IpAddress = answer->rrs.addr->addr.inet.sin_addr.s_addr;
850
851 adns_finish(astate);
852
853 (*QueryResultSet)->pName = (LPSTR)xstrsave(Name);
854
855 return (*QueryResultSet)->pName ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
856 }
857
858 if (NULL == answer || adns_s_prohibitedcname != answer->status || NULL == answer->cname)
859 {
860 adns_finish(astate);
861
862 if (CurrentName != AnsiName)
863 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
864
865 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
866 return ERROR_FILE_NOT_FOUND;
867 }
868
869 if (CurrentName != AnsiName)
870 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
871
872 CurrentName = (LPSTR)xstrsaveA(answer->cname);
873
874 if (!CurrentName)
875 {
876 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
877 adns_finish(astate);
878 return ERROR_OUTOFMEMORY;
879 }
880 }
881
882 adns_finish(astate);
883 RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiName);
884 RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentName);
885 return ERROR_FILE_NOT_FOUND;
886
887 default:
888 return ERROR_OUTOFMEMORY; /* XXX arty: find a better error code. */
889 }
890 }
891
892 DNS_STATUS WINAPI
893 DnsQuery_UTF8(LPCSTR Name,
894 WORD Type,
895 DWORD Options,
896 PIP4_ARRAY Servers,
897 PDNS_RECORD *QueryResultSet,
898 PVOID *Reserved)
899 {
900 UNIMPLEMENTED;
901 return ERROR_OUTOFMEMORY;
902 }
903
904 void
905 DnsIntFreeRecordList(PDNS_RECORD ToDelete)
906 {
907 UINT i;
908 PDNS_RECORD next = 0;
909
910 while(ToDelete)
911 {
912 if(ToDelete->pName)
913 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->pName);
914
915 switch(ToDelete->wType)
916 {
917 case DNS_TYPE_CNAME:
918 case DNS_TYPE_PTR:
919 case DNS_TYPE_NS:
920 case DNS_TYPE_MB:
921 case DNS_TYPE_MD:
922 case DNS_TYPE_MF:
923 case DNS_TYPE_MG:
924 case DNS_TYPE_MR:
925 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.PTR.pNameHost);
926 break;
927
928 case DNS_TYPE_MINFO:
929 case DNS_TYPE_MX:
930 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.MX.pNameExchange);
931 break;
932
933 case DNS_TYPE_HINFO:
934 for(i = 0; i < ToDelete->Data.TXT.dwStringCount; i++)
935 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray[i]);
936
937 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete->Data.TXT.pStringArray);
938 break;
939 }
940
941 next = ToDelete->pNext;
942 RtlFreeHeap(RtlGetProcessHeap(), 0, ToDelete);
943 ToDelete = next;
944 }
945 }