577 lines
10 KiB
C
577 lines
10 KiB
C
/*++
|
||
|
||
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
|
||
//
|