windows-nt/Source/XPSP1/NT/net/rras/ip/nathlp/dns/dnsfile.cpp
2020-09-26 16:20:57 +08:00

1016 lines
21 KiB
C++

/*++
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 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 == NULL))
{
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 == NULL))
{
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 == NULL))
{
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 == NULL))
{
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 == NULL))
{
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 == NULL))
{
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 == NULL))
{
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 == NULL))
{
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 = wcscmp(start, pszSuffix);
return (!ret);
} // IsSuffixValid
//
// End dnsfile.c
//