xref: /reactos/base/services/dnsrslvr/hostsfile.c (revision 7115d7ba)
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
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
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
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
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
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 *
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
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