/*++ Copyright (c) 1991-2000 Microsoft Corporation Module Name: hostfile.c Abstract: Reads host file into DNS cache. Author: Glenn Curtis (glennc) Picked up from winsock. Revision History: Jim Gilroy (jamesg) Feb 2000 Cleanup --*/ #include "local.h" #define HOSTS_FILE_DIRECTORY L"\\drivers\\etc" #if 0 // // Sockets hosts file stuff // #define HOSTDB_SIZE (_MAX_PATH + 8) // 8 == strlen("\\hosts") + 1 #define MAXALIASES 35 // // Globals // // Note: that none of this is MT safe. We assume that all these // functions are called only from a single thread (at startup) or // that some higher level locking is enabled. // FILE * g_HostFile = NULL; CHAR g_HostFileName[ HOSTDB_SIZE ]; CHAR g_HostLineBuf[ BUFSIZ+1 ]; PCHAR g_pHostName; PCHAR g_AliasArray[ MAXALIASES ]; BOOL g_IsIp6; IP_ADDRESS g_Ip4Address; DNS_IP6_ADDRESS g_Ip6Address; VOID _setfile( VOID ) /*++ Routine Description: Open hosts file. Arguments: None. Globals: g_HostFile -- host file ptr, tested and set Return Value: None. --*/ { if ( g_HostFile == NULL ) { g_HostFile = SockOpenNetworkDataBase( "hosts", g_HostFileName, HOSTDB_SIZE, "r" ); } else { rewind( g_HostFile ); } } VOID _endfile( VOID ) /*++ Routine Description: Close hosts file. Arguments: None. Globals: g_HostFile -- host file ptr, tested and cleared Return Value: None. --*/ { if ( g_HostFile ) { fclose( g_HostFile ); g_HostFile = NULL; } } BOOL _gethost( VOID ) /*++ Routine Description: Reads an entry from hosts file. Arguments: None. Globals: g_HostFile -- host file ptr, tested and set g_pHostName -- name ptr is set g_AliasArray -- alias ptr array is filled g_Ip4Address -- IP4 address is set g_Ip6Address -- IP6 address is set g_IsIp6 -- IP4\IP6 flag is set Return Value: TRUE if successfully reads a host entry. FALSE if on EOF or no hosts file found. --*/ { char *p; register char *cp, **q; // // open hosts file if not open // if ( g_HostFile == NULL && (g_HostFile = fopen(g_HostFileName, "r" )) == NULL ) { return FALSE; } // // loop until successfully read IP address // while( 1 ) { // quit on EOF if ((p = fgets(g_HostLineBuf, BUFSIZ, g_HostFile)) == NULL) { return FALSE; } // comment line -- skip if ( *p == '#' ) { continue; } // null address terminate at EOL or comment cp = strpbrk( p, "#\n" ); if ( cp != NULL ) { *cp = '\0'; } // all whitespace -- skip cp = strpbrk( p, " \t" ); if ( cp == NULL ) { continue; } // NULL terminate address string *cp++ = '\0'; // // read address // - try IP4 // - try IP6 // - otherwise skip // g_Ip4Address = inet_addr(p); if ( g_Ip4Address != INADDR_NONE || _strnicmp( "255.255.255.255", p, 15 ) == 0 ) { g_IsIp6 = FALSE; break; } // not valid IP4 -- check IP6 g_IsIp6 = Dns_Ipv6StringToAddress( & g_Ip6Address, p, 0 // null terminated string ); if ( g_IsIp6 ) { break; } // invalid address, ignore line DNSDBG( INIT, ( "Error parsing host file address %s\n", p )); continue; } // // find name // - skip leading whitespace // - set global name ptr while( *cp == ' ' || *cp == '\t' ) { cp++; } g_pHostName = cp; // stop at trailing whitespace, NULL terminate cp = strpbrk(cp, " \t"); if ( cp != NULL ) { *cp++ = '\0'; } // read aliases q = g_AliasArray; while ( cp && *cp ) { // skip leading whitespace if ( *cp == ' ' || *cp == '\t' ) { cp++; continue; } // save alias name to alias array if ( q < &g_AliasArray[MAXALIASES - 1] ) { *q++ = cp; } cp = strpbrk( cp, " \t" ); if ( cp != NULL ) { *cp++ = '\0'; } } *q = NULL; // successful entry read return TRUE; } VOID LoadHostFile( VOID ) /*++ Routine Description: Read hosts file into cache. Arguments: None. Globals: g_HostFile -- host file ptr, tested and set then cleared g_pHostName -- name ptr is read g_AliasArray -- alias ptr array is read g_Ip4Address -- IP4 address is read g_Ip6Address -- IP6 address is read g_IsIp6 -- IP4\IP6 flag is read Return Value: None. --*/ { register PCHAR * cp; DNSDBG( INIT, ( "Enter LoadHostFile\n" )); // // read entries from host file until exhausted // - cache A record for each name and alias // - cache PTR to name // _setfile(); while ( _gethost() ) { if ( g_pHostName ) { if ( g_IsIp6 ) { CacheAAAARecord( g_pHostName, g_Ip6Address ); } else { CacheARecord( g_pHostName, g_Ip4Address ); CachePtrRecord( g_Ip4Address, g_pHostName ); } } for ( cp = g_AliasArray; *cp != 0; cp++ ) { if ( g_IsIp6 ) { CacheAAAARecord( *cp, g_Ip6Address ); } else { CacheARecord( *cp, g_Ip4Address ); } } } _endfile(); DNSDBG( INIT, ( "Leave LoadHostFile\n" )); } #endif VOID HostsFileMonitorThread( VOID ) /*++ Routine Description: Main thread that waits on and reads host file changes. Arguments: None. Globals: g_hShutdownEvent -- waits on shutdown even Return Value: None. --*/ { BOOL bquitting = FALSE; HANDLE fileChangeHandle; DWORD waitResult; HANDLE changeHandles[2]; DWORD lockFlag = NO_LOCK; LPWSTR psystemDirectory = NULL; UINT len; WCHAR hostDirectory[ MAX_PATH*2 ]; DNSDBG( INIT, ( "Enter HostFileMonitorThread\n" )); // // build host file name // len = GetSystemDirectory( hostDirectory, MAX_PATH ); if ( !len || len>MAX_PATH ) { DNSLOG_F1( "Error: Failed to get system directory" ); DNSLOG_F1( "HostsFileMonitorThread exiting." ); return; } wcscat( hostDirectory, HOSTS_FILE_DIRECTORY ); // // drop change notify on host file directory // fileChangeHandle = FindFirstChangeNotification( hostDirectory, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE ); if ( fileChangeHandle == INVALID_HANDLE_VALUE ) { DNSLOG_F1( "HostsFileMonitorThread failed to get handle from" ); DNSLOG_F2( "FindFirstChangeNotification. Error code: <0x%.8X>", GetLastError() ); DNSLOG_F1( "HostsFileMonitorThread exiting." ); return; } // // wait on file notify OR shutdown // - on host file change rebuild cache and restart wait // - on shutdown, exit // changeHandles[0] = g_hShutdownEvent; changeHandles[1] = fileChangeHandle; while( 1 ) { waitResult = WaitForMultipleObjects( 2, changeHandles, FALSE, INFINITE ); switch( waitResult ) { case WAIT_OBJECT_0 : // shutdown event -- exit DNSLOG_F1( "HostsFileMonitorThread: Got event" ); DNSLOG_F1( "HostsFileMonitorStopEvent." ); goto ThreadExit; case WAIT_OBJECT_0 + 1 : // change notify -- flush cache and reload DNSLOG_F1( "HostsFileMonitorThread: Got HOSTS file" ); DNSLOG_F1( "directory change event." ); // reset notification -- BEFORE reload if ( !FindNextChangeNotification( fileChangeHandle ) ) { DNSLOG_F1( "HostsFileMonitorThread failed to get handle" ); DNSLOG_F1( "from FindNextChangeNotification." ); DNSLOG_F2( "Error code: <0x%.8X>", GetLastError() ); goto ThreadExit; } FlushCache( TRUE ); // flush and reload break; default: DNSLOG_F1( "HostsFileMonitorThread failed to get handle" ); goto ThreadExit; break; } } ThreadExit: // close change\notify handle CloseHandle( fileChangeHandle ); DNSDBG( INIT, ( "HostFileMonitorThread exit\n" )); DNSLOG_F1( "HostsFileMonitorThread exiting." ); } VOID LoadHostFileIntoCache( IN PSTR pFileName ) /*++ Routine Description: Read hosts file into cache. Arguments: pFileName -- file name to load Return Value: None. --*/ { HOST_FILE_INFO hostInfo; DNSDBG( INIT, ( "Enter LoadHostFile\n" )); // // read entries from host file until exhausted // - cache A record for each name and alias // - cache PTR to name // RtlZeroMemory( &hostInfo, sizeof(hostInfo) ); if ( !Dns_OpenHostFile( &hostInfo ) ) { return; } hostInfo.fBuildRecords = TRUE; while ( Dns_ReadHostFileLine( &hostInfo ) ) { // cache all the records we sucked out // // DCR: cache answer data with CNAME data CacheAnyAdditionalRecords( hostInfo.pForwardRR, TRUE ); CacheAnyAdditionalRecords( hostInfo.pReverseRR, TRUE ); CacheAnyAdditionalRecords( hostInfo.pAliasRR, TRUE ); } Dns_CloseHostFile( &hostInfo ); DNSDBG( INIT, ( "Leave LoadHostFile\n" )); } // // End hostfile.c //