1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: base/services/dnsrslvr/hostsfile.c
5 * PURPOSE: HOSTS file routines
6 * PROGRAMERS: Art Yerkes
7 * Eric Kohl
8 */
9
10 #include "precomp.h"
11 #include <inaddr.h>
12 #include <in6addr.h>
13
14
15 #define NDEBUG
16 #include <debug.h>
17
18 static WCHAR szHexChar[] = L"0123456789abcdef";
19
20 static
21 PWSTR
AnsiToUnicode(PSTR NarrowString)22 AnsiToUnicode(
23 PSTR NarrowString)
24 {
25 PWSTR WideString;
26 int WideLen;
27
28 WideLen = MultiByteToWideChar(CP_ACP,
29 0,
30 NarrowString,
31 -1,
32 NULL,
33 0);
34 if (WideLen == 0)
35 return NULL;
36
37 WideString = HeapAlloc(GetProcessHeap(),
38 0,
39 WideLen * sizeof(WCHAR));
40 if (WideString == NULL)
41 return NULL;
42
43 MultiByteToWideChar(CP_ACP,
44 0,
45 NarrowString,
46 -1,
47 WideString,
48 WideLen);
49
50 return WideString;
51 }
52
53
54 static
55 BOOL
ParseIpv4Address(_In_ PCSTR AddressString,_Out_ PIN_ADDR pAddress)56 ParseIpv4Address(
57 _In_ PCSTR AddressString,
58 _Out_ PIN_ADDR pAddress)
59 {
60 PCSTR pTerminator = NULL;
61 NTSTATUS Status;
62
63 Status = RtlIpv4StringToAddressA(AddressString,
64 TRUE,
65 &pTerminator,
66 pAddress);
67 if (NT_SUCCESS(Status) && pTerminator != NULL && *pTerminator == '\0')
68 return TRUE;
69
70 return FALSE;
71 }
72
73
74 static
75 BOOL
ParseIpv6Address(_In_ LPCSTR AddressString,_Out_ PIN6_ADDR pAddress)76 ParseIpv6Address(
77 _In_ LPCSTR AddressString,
78 _Out_ PIN6_ADDR pAddress)
79 {
80 PCSTR pTerminator = NULL;
81 NTSTATUS Status;
82
83 Status = RtlIpv6StringToAddressA(AddressString,
84 &pTerminator,
85 pAddress);
86 if (NT_SUCCESS(Status) && pTerminator != NULL && *pTerminator == '\0')
87 return TRUE;
88
89 return FALSE;
90 }
91
92
93 static
94 VOID
AddIpv4HostEntries(PWSTR pszHostName,PIN_ADDR pAddress)95 AddIpv4HostEntries(
96 PWSTR pszHostName,
97 PIN_ADDR pAddress)
98 {
99 DNS_RECORDW ARecord, PtrRecord;
100 WCHAR szReverseName[32];
101
102 /* Prepare the A record */
103 ZeroMemory(&ARecord, sizeof(DNS_RECORDW));
104
105 ARecord.pName = pszHostName;
106 ARecord.wType = DNS_TYPE_A;
107 ARecord.wDataLength = sizeof(DNS_A_DATA);
108 ARecord.Flags.S.Section = DnsSectionAnswer;
109 ARecord.Flags.S.CharSet = DnsCharSetUnicode;
110 ARecord.dwTtl = 86400;
111
112 ARecord.Data.A.IpAddress = pAddress->S_un.S_addr;
113
114 /* Prepare the PTR record */
115 swprintf(szReverseName,
116 L"%u.%u.%u.%u.in-addr.arpa.",
117 pAddress->S_un.S_un_b.s_b4,
118 pAddress->S_un.S_un_b.s_b3,
119 pAddress->S_un.S_un_b.s_b2,
120 pAddress->S_un.S_un_b.s_b1);
121
122 ZeroMemory(&PtrRecord, sizeof(DNS_RECORDW));
123
124 PtrRecord.pName = szReverseName;
125 PtrRecord.wType = DNS_TYPE_PTR;
126 PtrRecord.wDataLength = sizeof(DNS_PTR_DATA);
127 PtrRecord.Flags.S.Section = DnsSectionAnswer;
128 PtrRecord.Flags.S.CharSet = DnsCharSetUnicode;
129 PtrRecord.dwTtl = 86400;
130
131 PtrRecord.Data.PTR.pNameHost = pszHostName;
132
133 DnsIntCacheAddEntry(&ARecord, TRUE);
134 DnsIntCacheAddEntry(&PtrRecord, TRUE);
135 }
136
137
138 static
139 VOID
AddIpv6HostEntries(PWSTR pszHostName,PIN6_ADDR pAddress)140 AddIpv6HostEntries(
141 PWSTR pszHostName,
142 PIN6_ADDR pAddress)
143 {
144 DNS_RECORDW AAAARecord, PtrRecord;
145 WCHAR szReverseName[80];
146 DWORD i, j, k;
147
148 /* Prepare the AAAA record */
149 ZeroMemory(&AAAARecord, sizeof(DNS_RECORDW));
150
151 AAAARecord.pName = pszHostName;
152 AAAARecord.wType = DNS_TYPE_AAAA;
153 AAAARecord.wDataLength = sizeof(DNS_AAAA_DATA);
154 AAAARecord.Flags.S.Section = DnsSectionAnswer;
155 AAAARecord.Flags.S.CharSet = DnsCharSetUnicode;
156 AAAARecord.dwTtl = 86400;
157
158 CopyMemory(&AAAARecord.Data.AAAA.Ip6Address,
159 &pAddress->u.Byte,
160 sizeof(IN6_ADDR));
161
162 /* Prepare the PTR record */
163 ZeroMemory(szReverseName, sizeof(szReverseName));
164
165 for (i = 0; i < sizeof(IN6_ADDR); i++)
166 {
167 j = 4 * i;
168 k = sizeof(IN6_ADDR) - 1 - i;
169 szReverseName[j] = szHexChar[pAddress->u.Byte[k] & 0xF];
170 szReverseName[j + 1] = L'.';
171 szReverseName[j + 2] = szHexChar[(pAddress->u.Byte[k] >> 4) & 0xF];
172 szReverseName[j + 3] = L'.';
173 }
174 wcscat(szReverseName, L"ip6.arpa.");
175
176 ZeroMemory(&PtrRecord, sizeof(DNS_RECORDW));
177
178 PtrRecord.pName = szReverseName;
179 PtrRecord.wType = DNS_TYPE_PTR;
180 PtrRecord.wDataLength = sizeof(DNS_PTR_DATA);
181 PtrRecord.Flags.S.Section = DnsSectionAnswer;
182 PtrRecord.Flags.S.CharSet = DnsCharSetUnicode;
183 PtrRecord.dwTtl = 86400;
184
185 PtrRecord.Data.PTR.pNameHost = pszHostName;
186
187 DnsIntCacheAddEntry(&AAAARecord, TRUE);
188 DnsIntCacheAddEntry(&PtrRecord, TRUE);
189 }
190
191
192 static
193 FILE *
OpenHostsFile(VOID)194 OpenHostsFile(VOID)
195 {
196 PWSTR ExpandedPath;
197 PWSTR DatabasePath;
198 HKEY DatabaseKey;
199 DWORD RegSize = 0;
200 size_t StringLength;
201 FILE *pHostsFile;
202 DWORD dwError;
203
204 ExpandedPath = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
205 if (ExpandedPath == NULL)
206 return NULL;
207
208 /* Open the database path key */
209 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
210 L"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
211 0,
212 KEY_READ,
213 &DatabaseKey);
214 if (dwError == ERROR_SUCCESS)
215 {
216 /* Read the actual path */
217 RegQueryValueExW(DatabaseKey,
218 L"DatabasePath",
219 NULL,
220 NULL,
221 NULL,
222 &RegSize);
223
224 DatabasePath = HeapAlloc(GetProcessHeap(), 0, RegSize);
225 if (DatabasePath == NULL)
226 {
227 HeapFree(GetProcessHeap(), 0, ExpandedPath);
228 RegCloseKey(DatabaseKey);
229 return NULL;
230 }
231
232 /* Read the actual path */
233 dwError = RegQueryValueExW(DatabaseKey,
234 L"DatabasePath",
235 NULL,
236 NULL,
237 (LPBYTE)DatabasePath,
238 &RegSize);
239
240 /* Close the key */
241 RegCloseKey(DatabaseKey);
242
243 if (dwError != ERROR_SUCCESS)
244 {
245 HeapFree(GetProcessHeap(), 0, DatabasePath);
246 HeapFree(GetProcessHeap(), 0, ExpandedPath);
247 return NULL;
248 }
249
250 /* Expand the name */
251 ExpandEnvironmentStringsW(DatabasePath, ExpandedPath, MAX_PATH);
252
253 HeapFree(GetProcessHeap(), 0, DatabasePath);
254 }
255 else
256 {
257 /* Use defalt path */
258 GetSystemDirectoryW(ExpandedPath, MAX_PATH);
259
260 StringCchLengthW(ExpandedPath, MAX_PATH, &StringLength);
261 if (ExpandedPath[StringLength - 1] != L'\\')
262 {
263 /* It isn't, so add it ourselves */
264 StringCchCatW(ExpandedPath, MAX_PATH, L"\\");
265 }
266
267 StringCchCatW(ExpandedPath, MAX_PATH, L"drivers\\etc\\");
268 }
269
270 /* Make sure that the path is backslash-terminated */
271 StringCchLengthW(ExpandedPath, MAX_PATH, &StringLength);
272 if (ExpandedPath[StringLength - 1] != L'\\')
273 {
274 /* It isn't, so add it ourselves */
275 StringCchCatW(ExpandedPath, MAX_PATH, L"\\");
276 }
277
278 /* Add the database name */
279 StringCchCatW(ExpandedPath, MAX_PATH, L"hosts");
280
281 /* Open the hosts file */
282 pHostsFile = _wfopen(ExpandedPath, L"r");
283
284 HeapFree(GetProcessHeap(), 0, ExpandedPath);
285
286 return pHostsFile;
287 }
288
289
290 BOOL
ReadHostsFile(VOID)291 ReadHostsFile(VOID)
292 {
293 CHAR szLineBuffer[512];
294 FILE *pHostFile = NULL;
295 CHAR *Ptr, *NameStart, *NameEnd, *AddressStart, *AddressEnd;
296 struct in_addr Ipv4Address;
297 struct in6_addr Ipv6Address;
298 PWSTR pszHostName;
299
300 pHostFile = OpenHostsFile();
301 if (pHostFile == NULL)
302 return FALSE;
303
304 for (;;)
305 {
306 /* Read a line */
307 if (fgets(szLineBuffer, sizeof(szLineBuffer), pHostFile) == NULL)
308 break;
309
310 NameStart = NameEnd = NULL;
311 AddressStart = AddressEnd = NULL;
312
313 /* Search for the start of the ip address */
314 Ptr = szLineBuffer;
315 for (;;)
316 {
317 if (*Ptr == 0 || *Ptr == '#')
318 break;
319
320 if (!isspace(*Ptr))
321 {
322 AddressStart = Ptr;
323 Ptr = Ptr + 1;
324 break;
325 }
326
327 Ptr = Ptr + 1;
328 }
329
330 /* Search for the end of the ip address */
331 for (;;)
332 {
333 if (*Ptr == 0 || *Ptr == '#')
334 break;
335
336 if (isspace(*Ptr))
337 {
338 AddressEnd = Ptr;
339 Ptr = Ptr + 1;
340 break;
341 }
342
343 Ptr = Ptr + 1;
344 }
345
346 /* Search for the start of the name */
347 for (;;)
348 {
349 if (*Ptr == 0 || *Ptr == '#')
350 break;
351
352 if (!isspace(*Ptr))
353 {
354 NameStart = Ptr;
355 Ptr = Ptr + 1;
356 break;
357 }
358
359 Ptr = Ptr + 1;
360 }
361
362 /* Search for the end of the name */
363 for (;;)
364 {
365 if (*Ptr == 0 || *Ptr == '#')
366 break;
367
368 if (isspace(*Ptr))
369 {
370 NameEnd = Ptr;
371 break;
372 }
373
374 Ptr = Ptr + 1;
375 }
376
377 if (AddressStart == NULL || AddressEnd == NULL ||
378 NameStart == NULL || NameEnd == NULL)
379 continue;
380
381 *AddressEnd = 0;
382 *NameEnd = 0;
383
384 DPRINT("%s ==> %s\n", NameStart, AddressStart);
385
386 if (ParseIpv4Address(AddressStart, &Ipv4Address))
387 {
388 DPRINT("IPv4: %s\n", AddressStart);
389
390 pszHostName = AnsiToUnicode(NameStart);
391 if (pszHostName != NULL)
392 {
393 AddIpv4HostEntries(pszHostName, &Ipv4Address);
394 HeapFree(GetProcessHeap(), 0, pszHostName);
395 }
396 }
397 else if (ParseIpv6Address(AddressStart, &Ipv6Address))
398 {
399 DPRINT("IPv6: %s\n", AddressStart);
400
401 pszHostName = AnsiToUnicode(NameStart);
402 if (pszHostName != NULL)
403 {
404 AddIpv6HostEntries(pszHostName, &Ipv6Address);
405 HeapFree(GetProcessHeap(), 0, pszHostName);
406 }
407 }
408 }
409
410 fclose(pHostFile);
411
412 return TRUE;
413 }
414
415 /* EOF */
416