|
|
/*++
Copyright (c) 2000, Microsoft Corporation
Module Name:
dnsfile.c
Abstract:
This module contains code for the Simple DNS Server (formerly the DNS Proxy) to operate on the Hosts.ics file. Abridged from the DS tree.
Author:
Raghu Gatta (rgatta) 15-Nov-2000
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// EXTERNAL DECLARATIONS
//
extern "C" FILE * SockOpenNetworkDataBase( IN char *Database, OUT char *Pathname, IN int PathnameLen, IN char *OpenFlags );
//
// Locking Order:
// (1) DnsFileInfo.Lock
// (2) DnsTableLock
// OR
// (1) DnsGlobalInfoLock
// (2) DnsTableLock
//
// Globals
//
IP_DNS_PROXY_FILE_INFO DnsFileInfo;
ULONG DnsInitializeFileManagement( VOID )
/*++
Routine Description:
This routine is called to initialize the file management module.
Arguments:
none.
Return Value:
ULONG - Win32 status code.
Environment:
Invoked internally in the context of an IP router-manager thread. (See 'RMDNS.C').
--*/
{ ULONG Error = NO_ERROR; PROFILE("DnsInitializeFileManagement");
ZeroMemory(&DnsFileInfo, sizeof(IP_DNS_PROXY_FILE_INFO));
__try { InitializeCriticalSection(&DnsFileInfo.Lock); } __except(EXCEPTION_EXECUTE_HANDLER) { NhTrace( TRACE_FLAG_IF, "DnsInitializeFileManagement: exception %d creating lock", Error = GetExceptionCode() ); }
return Error;
} // DnsInitializeFileManagement
VOID DnsShutdownFileManagement( VOID )
/*++
Routine Description:
This routine is called to shutdown the file management module.
Arguments:
none.
Return Value:
none.
Environment:
Invoked in an arbitrary thread context.
--*/
{ PROFILE("DnsShutdownFileManagement");
DnsEndHostsIcsFile();
DeleteCriticalSection(&DnsFileInfo.Lock);
} // DnsShutdownFileManagement
BOOL DnsEndHostsIcsFile( VOID ) /*++
Routine Description:
Close hosts file.
Arguments:
None.
Globals:
DnsFileInfo.HostFile -- host file ptr, tested and cleared
Return Value:
None.
--*/ { if (DnsFileInfo.HostFile) { fclose(DnsFileInfo.HostFile); DnsFileInfo.HostFile = NULL; }
return TRUE; } // DnsEndHostsIcsFile
BOOL DnsSetHostsIcsFile( BOOL fOverwrite ) /*++
Routine Description:
Open hosts.ics file. If we write, we overwrite, else we read
Arguments:
None.
Globals:
DnsFileInfo.HostFile -- host file ptr, tested and set
Return Value:
None.
--*/ { LPVOID lpMsgBuf; UINT len; WCHAR hostDirectory[MAX_PATH*2]; PCHAR mode = fOverwrite ? "w+t" : "rt";
DnsEndHostsIcsFile();
//
// reset the host file name to hosts.ics
//
ZeroMemory(DnsFileInfo.HostFileName, HOSTDB_SIZE);
DnsFileInfo.HostFile = SockOpenNetworkDataBase( HOSTSICSFILE, DnsFileInfo.HostFileName, HOSTDB_SIZE, mode ); if(DnsFileInfo.HostFile == NULL) { NhTrace( TRACE_FLAG_DNS, "DnsSetHostsIcsFile: Unable to open %s file", HOSTSICSFILE ); return FALSE; } else { /*
NhTrace( TRACE_FLAG_DNS, "DnsSetHostsIcsFile: Successfully opened %s file", DnsFileInfo.HostFileName ); */ }
return TRUE; } // DnsSetHostsIcsFile
BOOL GetHostFromHostsIcsFile( BOOL fStartup ) /*++
Routine Description:
Reads an entry from hosts.ics file.
Arguments:
fStartup set to TRUE if called on startup of protocol
Globals:
DnsFileInfo.HostFile -- host file ptr, tested and set DnsFileInfo.HostTime -- host timestamp DnsFileInfo.pHostName -- name ptr is set DnsFileInfo.Ip4Address -- IP4 address is set
Return Value:
TRUE if we were able to successfully able to read a line. FALSE if on EOF or no hosts file found.
--*/ { char *p, *ep; register char *cp, **q;
//
// we assume the hosts.ics file has already been opened
//
if (DnsFileInfo.HostFile == NULL) { return FALSE; }
DnsFileInfo.HostLineBuf[BUFSIZ] = NULL; DnsFileInfo.pHostName = NULL; DnsFileInfo.Ip4Address = 0; ZeroMemory(&DnsFileInfo.HostTime, sizeof(SYSTEMTIME));
//
// loop until successfully read IP address
// IP address starts on column 1
//
while( 1 ) { // quit on EOF
if ((p = fgets(DnsFileInfo.HostLineBuf, BUFSIZ, DnsFileInfo.HostFile)) == NULL) { if (!feof(DnsFileInfo.HostFile)) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error reading line" ); } return FALSE; }
// comment line -- skip
if (*p == '#') { p++;
//
// if in startup mode, we skip first comment sign;
// if there are more comment signs -- skip
//
if ((fStartup && *p == '#') || !fStartup) { continue; } }
// null address terminate at EOL
cp = strpbrk(p, "\n"); if (cp != NULL) { *cp = '\0'; }
// whole line is characters - no whitespace -- skip
cp = strpbrk(p, " \t"); if ( cp == NULL ) { continue; }
// NULL terminate address string
*cp++ = '\0';
//
// read address
// - try IP4
// - ignore IP6 for now
// - otherwise skip
//
DnsFileInfo.Ip4Address = inet_addr(p);
if (DnsFileInfo.Ip4Address != INADDR_NONE || _strnicmp("255.255.255.255", p, 15) == 0) { break; }
// invalid address, ignore line
//
// debug tracing
//
NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host file address %s", p ); continue; }
// find the end of the string which was read
ep = cp; while( *ep ) ep++;
//
// find name
// - skip leading whitespace
// - set global name ptr
//
while( *cp == ' ' || *cp == '\t' ) cp++; DnsFileInfo.pHostName = cp;
// stop at trailing whitespace, NULL terminate
cp = strpbrk(cp, " \t"); if ( cp != NULL ) { *cp++ = '\0'; } else { // we have a name - but no timestamp
NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp", DnsFileInfo.pHostName ); goto Failed; }
// we dont have any support for aliases
//
// find the timestamp
// - skip leading whitespace
// - read the time values
//
while( *cp == ' ' || *cp == '\t' ) cp++;
if ((cp >= ep) || (*cp != '#')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp", DnsFileInfo.pHostName ); goto Failed; } cp++;
while( *cp == ' ' || *cp == '\t' ) cp++; // now at first system time value
if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 1", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wYear = (WORD) atoi(cp); cp = strpbrk(cp, " \t"); if (cp == NULL) goto Failed; while( *cp == ' ' || *cp == '\t' ) cp++; if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 2", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wMonth = (WORD) atoi(cp); cp = strpbrk(cp, " \t"); if (cp == NULL) goto Failed;
while( *cp == ' ' || *cp == '\t' ) cp++; if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 3", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wDayOfWeek = (WORD) atoi(cp); cp = strpbrk(cp, " \t"); if (cp == NULL) goto Failed;
while( *cp == ' ' || *cp == '\t' ) cp++; if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 4", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wDay = (WORD) atoi(cp); cp = strpbrk(cp, " \t"); if (cp == NULL) goto Failed;
while( *cp == ' ' || *cp == '\t' ) cp++; if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 5", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wHour = (WORD) atoi(cp); cp = strpbrk(cp, " \t"); if (cp == NULL) goto Failed;
while( *cp == ' ' || *cp == '\t' ) cp++; if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 6", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wMinute = (WORD) atoi(cp); cp = strpbrk(cp, " \t"); if (cp == NULL) goto Failed;
while( *cp == ' ' || *cp == '\t' ) cp++; if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 7", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wSecond = (WORD) atoi(cp); cp = strpbrk(cp, " \t"); if (cp == NULL) goto Failed;
while( *cp == ' ' || *cp == '\t' ) cp++; if ((cp >= ep) || (*cp == '\0')) { NhTrace( TRACE_FLAG_DNS, "GetHostFromHostsIcsFile: Error parsing host (%s) file timestamp @ 8", DnsFileInfo.pHostName ); goto Failed; } DnsFileInfo.HostTime.wMilliseconds = (WORD) atoi(cp);
//
// successful entry read
//
/*
NhTrace( TRACE_FLAG_DNS, "%s (%s) has timestamp: %04u-%02u-%02u %02u:%02u:%02u", DnsFileInfo.pHostName, inet_ntoa(*(PIN_ADDR)&DnsFileInfo.Ip4Address), DnsFileInfo.HostTime.wYear, DnsFileInfo.HostTime.wMonth, DnsFileInfo.HostTime.wDay, DnsFileInfo.HostTime.wHour, DnsFileInfo.HostTime.wMinute, DnsFileInfo.HostTime.wSecond ); */ return TRUE;
Failed:
// reset entries
DnsFileInfo.HostLineBuf[0] = NULL; DnsFileInfo.pHostName = NULL; DnsFileInfo.Ip4Address = 0; ZeroMemory(&DnsFileInfo.HostTime, sizeof(SYSTEMTIME));
return TRUE; } // GetHostFromHostsIcsFile
VOID LoadHostsIcsFile( BOOL fStartup ) /*++
Routine Description:
Read hosts file into our local cache.
Arguments:
fStartup set to TRUE if called on startup of protocol
Globals:
DnsFileInfo.HostFile -- host file ptr, tested and set then cleared DnsFileInfo.HostTime -- host timestamp DnsFileInfo.pHostName -- name ptr is read DnsFileInfo.Ip4Address -- IP4 address is read
Return Value:
None.
--*/ { register PCHAR * cp; FILETIME ftExpires; PWCHAR pszName; LPVOID lpMsgBuf;
NhTrace( TRACE_FLAG_DNS, "LoadHostsIcsFile: Entering..." );
ACQUIRE_LOCK(&DnsFileInfo);
//
// read entries from host file until exhausted
//
DnsSetHostsIcsFile(FALSE); // read only
while (GetHostFromHostsIcsFile(fStartup)) { if (DnsFileInfo.pHostName) { if (!SystemTimeToFileTime(&DnsFileInfo.HostTime, &ftExpires)) { DWORD dwLastError = GetLastError(); NhTrace( TRACE_FLAG_DNS, "LoadHostsIcsFile: SystemTimeToFileTime() failed" );
lpMsgBuf = NULL; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); NhTrace( TRACE_FLAG_DNS, "LoadHostsIcsFile: with message (0x%08x) %S", dwLastError, lpMsgBuf ); if (lpMsgBuf) LocalFree(lpMsgBuf);
// skip entry
continue; }
pszName = (PWCHAR) NH_ALLOCATE((strlen(DnsFileInfo.pHostName) + 1) * sizeof(WCHAR));
mbstowcs(pszName, DnsFileInfo.pHostName, (strlen(DnsFileInfo.pHostName) + 1));
NhTrace( TRACE_FLAG_DNS, "%S (%s) has timestamp: %04u-%02u-%02u %02u:%02u:%02u", pszName, inet_ntoa(*(PIN_ADDR)&DnsFileInfo.Ip4Address), DnsFileInfo.HostTime.wYear, DnsFileInfo.HostTime.wMonth, DnsFileInfo.HostTime.wDay, DnsFileInfo.HostTime.wHour, DnsFileInfo.HostTime.wMinute, DnsFileInfo.HostTime.wSecond );
DnsAddAddressForName( pszName, DnsFileInfo.Ip4Address, ftExpires );
NH_FREE(pszName); }
}
DnsEndHostsIcsFile();
RELEASE_LOCK(&DnsFileInfo);
//
// now that we have everything in our table format,
// write back a clean version to disk
//
SaveHostsIcsFile(FALSE);
NhTrace( TRACE_FLAG_DNS, "LoadHostsIcsFile: ...Leaving." );
} // LoadHostsIcsFile
VOID SaveHostsIcsFile( BOOL fShutdown ) /*++
Routine Description:
Write hosts file from our local cache.
Arguments:
fShutdown set to TRUE if called on shutdown of protocol
Globals:
DnsFileInfo.HostFile -- host file ptr, tested and set then cleared DnsFileInfo.HostTime -- host timestamp DnsFileInfo.pHostName -- name ptr is read DnsFileInfo.Ip4Address -- IP4 address is read
Return Value:
None.
--*/ { //DWORD dwSize = 0;
//PWCHAR pszSuffix = NULL;
UINT i; SYSTEMTIME stTime; LPVOID lpMsgBuf; NhTrace( TRACE_FLAG_DNS, "SaveHostsIcsFile: Entering..." );
//
// adding ourself as a special case
//
DnsAddSelf();
//
// get a copy of current ICS Domain suffix (used later on)
// we dont play with it directly from the global copy
// due to locking problems
//
/*
EnterCriticalSection(&DnsGlobalInfoLock);
if (DnsICSDomainSuffix) { dwSize = wcslen(DnsICSDomainSuffix) + 1;
pszSuffix = reinterpret_cast<PWCHAR>( NH_ALLOCATE(sizeof(WCHAR) * dwSize) ); if (!pszSuffix) { NhTrace( TRACE_FLAG_DNS, "SaveHostsIcsFile: allocation failed for " "DnsICSDomainSuffix copy" ); } else { wcscpy(pszSuffix, DnsICSDomainSuffix); } } LeaveCriticalSection(&DnsGlobalInfoLock); */
ACQUIRE_LOCK(&DnsFileInfo);
//
// write entries into host file
//
DnsSetHostsIcsFile(TRUE); // overwrite existing file if any
if (DnsFileInfo.HostFile != NULL) { //
// write default header string
//
if (fShutdown) { // add extra # at front
fputc('#', DnsFileInfo.HostFile); } fputs(HOSTSICSFILE_HEADER, DnsFileInfo.HostFile);
PDNS_ENTRY pDnsEntry;
EnterCriticalSection(&DnsTableLock);
pDnsEntry = (PDNS_ENTRY) RtlEnumerateGenericTable(&g_DnsTable, TRUE);
while (pDnsEntry != NULL) {
for (i = 0; i < pDnsEntry->cAddresses; i++) { //
// dont add entries with invalid suffixes
// (this could happen for example because the suffix
// was changed in the registry)
//
//if (!IsSuffixValid(pDnsEntry->pszName, pszSuffix))
//{
// continue;
//}
//
// dont add expired entries to the hosts.ics file
//
if (IsFileTimeExpired(&pDnsEntry->aAddressInfo[i].ftExpires)) { continue; }
if (!FileTimeToSystemTime( &pDnsEntry->aAddressInfo[i].ftExpires, &stTime)) { NhTrace( TRACE_FLAG_DNS, "SaveHostsIcsFile: FileTimeToSystemTime() failed" );
lpMsgBuf = NULL; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); NhTrace( TRACE_FLAG_DNS, "SaveHostsIcsFile: with message %S", lpMsgBuf ); if (lpMsgBuf) LocalFree(lpMsgBuf);
// skip entry
continue; }
if (fShutdown) { // add extra # at front
fputc('#', DnsFileInfo.HostFile); } fprintf( DnsFileInfo.HostFile, "%s %S # %u %u %u %u %u %u %u %u\n", inet_ntoa(*(PIN_ADDR)&pDnsEntry->aAddressInfo[i].ulAddress), pDnsEntry->pszName, stTime.wYear, stTime.wMonth, stTime.wDayOfWeek, stTime.wDay, stTime.wHour, stTime.wMinute, stTime.wSecond, stTime.wMilliseconds );
NhTrace( TRACE_FLAG_DNS, "adding entry: %s %S # %u %u %u %u %u %u %u %u\n", inet_ntoa(*(PIN_ADDR)&pDnsEntry->aAddressInfo[i].ulAddress), pDnsEntry->pszName, stTime.wYear, stTime.wMonth, stTime.wDayOfWeek, stTime.wDay, stTime.wHour, stTime.wMinute, stTime.wSecond, stTime.wMilliseconds ); }
pDnsEntry = (PDNS_ENTRY) RtlEnumerateGenericTable(&g_DnsTable, FALSE);
}
LeaveCriticalSection(&DnsTableLock); }
DnsEndHostsIcsFile();
RELEASE_LOCK(&DnsFileInfo);
/*
if (pszSuffix) { NH_FREE(pszSuffix); pszSuffix = NULL; } */
NhTrace( TRACE_FLAG_DNS, "SaveHostsIcsFile: ...Leaving." );
} // SaveHostsIcsFile
BOOL IsFileTimeExpired( FILETIME *ftTime ) { ULARGE_INTEGER uliTime, uliNow; FILETIME ftNow;
GetSystemTimeAsFileTime(&ftNow); memcpy(&uliNow, &ftNow, sizeof(ULARGE_INTEGER)); memcpy(&uliTime, ftTime, sizeof(ULARGE_INTEGER));
return (uliTime.QuadPart < uliNow.QuadPart); } // IsFileTimeExpired
BOOL IsSuffixValid( WCHAR *pszName, WCHAR *pszSuffix )
/*++
Routine Description:
This routine is invoked to compare suffix on the end of the name with what the DNS component thinks of as the current suffix.
Arguments:
none.
Return Value:
TRUE or FALSE.
Environment:
Invoked in an arbitrary context.
--*/
{ BOOL ret; PWCHAR start = pszName; size_t lenName = 0, lenSuffix = 0;
if (!start) { return FALSE; }
lenName = wcslen(pszName); lenSuffix = wcslen(pszSuffix);
if (!lenName || !lenSuffix) { return FALSE; }
if (lenName < lenSuffix) { return FALSE; }
lenName -= lenSuffix;
while (lenName--) start++;
ret = _wcsicmp(start, pszSuffix);
return (!ret); } // IsSuffixValid
//
// End dnsfile.c
//
|