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