|
|
/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
hostfile.c
Abstract:
Read host file data.
Author:
Jim Gilroy (jamesg) October 2000
Revision History:
--*/
#include "local.h"
// sockreg.h includes "etc" directory file opens
// sockreg.h is NT file so must define NTSTATUS first
#ifndef NTSTATUS
#define NTSTATUS LONG
#endif
#include <sockreg.h>
//
// Host file defs
// Note, HOST_FILE_INFO blob defined in dnsapip.h
//
#define HOST_FILE_PATH_LENGTH (MAX_PATH + sizeof("\\hosts") + 1)
//
// Host file record TTL
// (use a week)
//
#define HOSTFILE_RECORD_TTL (604800)
BOOL Dns_OpenHostFile( IN OUT PHOST_FILE_INFO pHostInfo ) /*++
Routine Description:
Open hosts file or rewind existing file to beginning.
Arguments:
pHostInfo - ptr to host info;
hFile - must be NULL if file not previously opened otherwise hFile is assumed to be existing FILE pointer
pszFileName - NULL to open "hosts" file otherwise is name of file to open
Return Value:
None.
--*/ { CHAR hostFileNameBuffer[ HOST_FILE_PATH_LENGTH ];
DNSDBG( TRACE, ( "Dns_OpenHostFile()\n" ));
//
// open host file OR rewind if already open
//
if ( pHostInfo->hFile == NULL ) { PSTR pnameFile = pHostInfo->pszFileName;
if ( !pnameFile ) { pnameFile = "hosts"; }
pHostInfo->hFile = SockOpenNetworkDataBase( pnameFile, hostFileNameBuffer, HOST_FILE_PATH_LENGTH, "r" ); } else { rewind( pHostInfo->hFile ); }
return ( pHostInfo->hFile ? TRUE : FALSE ); }
VOID Dns_CloseHostFile( IN OUT PHOST_FILE_INFO pHostInfo ) /*++
Routine Description:
Close hosts file.
Arguments:
pHostInfo -- ptr to host info; hFile assumed to contain file pointer
Return Value:
None.
--*/ { DNSDBG( TRACE, ( "Dns_CloseHostFile()\n" ));
if ( pHostInfo->hFile ) { fclose( pHostInfo->hFile ); pHostInfo->hFile = NULL; } }
VOID BuildHostfileRecords( IN OUT PHOST_FILE_INFO pHostInfo ) /*++
Routine Description:
Build records from hostfile line.
Arguments:
pHostInfo -- ptr to host info
Return Value:
TRUE if successful. FALSE on error.
--*/ { DNS_LIST aliasList; PCHAR * paliasEntry; PCHAR palias; PDNS_RECORD prr;
DNSDBG( TRACE, ( "BuildHostfileRecords()\n" ));
//
// create all the records
// - A or AAAA for name
// - CNAMEs for aliases
// - PTR
//
// for hosts file records
// - section == ANSWER
// - hostsfile flag set
//
prr = Dns_CreateForwardRecord( pHostInfo->pHostName, & pHostInfo->Ip, HOSTFILE_RECORD_TTL, DnsCharSetAnsi, DnsCharSetUnicode );
pHostInfo->pForwardRR = prr; if ( prr ) { SET_RR_HOSTS_FILE( prr ); prr->Flags.S.Section = DnsSectionAnswer; }
//
// build aliases into list of CNAME records
// - append forward lookup answer with each CNAME
//
DNS_LIST_STRUCT_INIT( aliasList );
for( paliasEntry = pHostInfo->AliasArray; palias = *paliasEntry; paliasEntry++ ) { PDNS_RECORD prrForward = pHostInfo->pForwardRR; PDNS_RECORD prrAnswer;
DNSDBG( INIT, ( "Building for alias %s for hostname %s\n", palias, pHostInfo->pHostName ));
prr = Dns_CreatePtrTypeRecord( palias, TRUE, // make name copy
pHostInfo->pHostName, DNS_TYPE_CNAME, HOSTFILE_RECORD_TTL, DnsCharSetAnsi, DnsCharSetUnicode ); if ( prr ) { SET_RR_HOSTS_FILE( prr ); prr->Flags.S.Section = DnsSectionAnswer; DNS_LIST_STRUCT_ADD( aliasList, prr );
// append forward record
if ( prrForward && (prrAnswer = Dns_RecordCopy_W(prrForward)) ) { DNS_LIST_STRUCT_ADD( aliasList, prrAnswer ); } } }
pHostInfo->pAliasRR = aliasList.pFirst;
//
// PTR points only to name
//
prr = Dns_CreatePtrRecordEx( & pHostInfo->Ip, pHostInfo->pHostName, // target name
HOSTFILE_RECORD_TTL, DnsCharSetAnsi, DnsCharSetUnicode );
pHostInfo->pReverseRR = prr; if ( prr ) { SET_RR_HOSTS_FILE( prr ); prr->Flags.S.Section = DnsSectionAnswer; }
IF_DNSDBG( QUERY ) { DnsDbg_RecordSet( "HostFile forward record:", pHostInfo->pForwardRR );
DnsDbg_RecordSet( "HostFile reverse record:", pHostInfo->pReverseRR );
if ( pHostInfo->pAliasRR ) { DnsDbg_RecordSet( "HostFile alias records:", pHostInfo->pAliasRR ); } } }
BOOL TokenizeHostFileLine( IN OUT PHOST_FILE_INFO pHostInfo ) /*++
Routine Description:
Reads an entry from hosts file.
Arguments:
pHostInfo -- ptr to host info; if hFile is NULL, first attempts host file open other fields are filled with info from next hostfile line
Return Value:
TRUE if successfully tokenized line. FALSE on empty or bad line
--*/ { PCHAR pch; PCHAR ptoken; DWORD countAlias = 0; DWORD count = 0;
DNSDBG( TRACE, ( "TokenizeHostFileLine()\n" ));
//
// tokenize line
//
pch = pHostInfo->HostLineBuf;
while( pch ) { // strip leading whitespace
while( *pch == ' ' || *pch == '\t' ) { pch++; } ptoken = pch;
//
// NULL terminate token
// - NULL pch serves as signal to stop after this token
//
pch = strpbrk( pch, " \t#\n\r" ); if ( pch != NULL ) { // empty (zero-length) token => done now
if ( pch == ptoken ) { break; }
// terminated by whitespace -- may be another token
if ( *pch == ' ' || *pch == '\t' ) { *pch++ = '\0'; }
// terminated by EOL -- no more tokens
else // #\r\n
{ *pch = '\0'; pch = NULL; } } count++;
//
// save address, name or alias
//
if ( count == 1 ) { pHostInfo->pAddrString = ptoken; } else if ( count == 2 ) { pHostInfo->pHostName = ptoken; } else { if ( countAlias >= MAXALIASES ) { break; } pHostInfo->AliasArray[ countAlias++ ] = ptoken; } }
// NULL terminate alias array
pHostInfo->AliasArray[ countAlias ] = NULL;
IF_DNSDBG( INIT ) { if ( count >= 2 ) { PSTR palias;
DnsDbg_Printf( "Parsed host file line:\n" "\tAddress = %s\n" "\tHostname = %s\n", pHostInfo->pAddrString, pHostInfo->pHostName );
countAlias = 0; while ( palias = pHostInfo->AliasArray[countAlias] ) { DnsDbg_Printf( "\tAlias = %s\n", palias ); countAlias++; } } }
return( count >= 2 ); }
BOOL Dns_ReadHostFileLine( IN OUT PHOST_FILE_INFO pHostInfo ) /*++
Routine Description:
Reads an entry from hosts file.
Arguments:
pHostInfo -- ptr to host info; if hFile is NULL, first attempts host file open other fields are filled with info from next hostfile line
Return Value:
TRUE if successfully reads a host entry. FALSE if on EOF or no hosts file found.
--*/ { IP4_ADDRESS ip4; DNS_IP6_ADDRESS ip6;
DNSDBG( TRACE, ( "Dns_ReadHostFileLine()\n" ));
//
// open hosts file if not open
//
if ( pHostInfo->hFile == NULL ) { Dns_OpenHostFile( pHostInfo ); if ( pHostInfo->hFile == NULL ) { return FALSE; } }
//
// loop until successfully read IP address
//
while( 1 ) { // setup for next line
pHostInfo->pForwardRR = NULL; pHostInfo->pReverseRR = NULL; pHostInfo->pAliasRR = NULL;
// read line, quit on EOF
if ( ! fgets( pHostInfo->HostLineBuf, sizeof(pHostInfo->HostLineBuf) - 1, pHostInfo->hFile ) ) { return FALSE; }
// tokenize line
if ( !TokenizeHostFileLine( pHostInfo ) ) { continue; }
//
// read address
// - try IP4
// - try IP6
// - otherwise skip
//
ip4 = inet_addr( pHostInfo->pAddrString );
if ( ip4 != INADDR_NONE || _strnicmp( "255.255.255.255", pHostInfo->pAddrString, 15 ) == 0 ) { IPUNION_SET_IP4( &pHostInfo->Ip, ip4 ); break; }
// not valid IP4 -- check IP6
if ( Dns_Ip6StringToAddress_A( & ip6, pHostInfo->pAddrString ) ) { IPUNION_SET_IP6( &pHostInfo->Ip, ip6 ); break; }
// invalid address, ignore line
DNSDBG( INIT, ( "Error parsing host file address %s\n", pHostInfo->pAddrString )); continue; }
//
// build records for line if desired
//
if ( pHostInfo->fBuildRecords ) { BuildHostfileRecords( pHostInfo ); }
return TRUE; }
BOOL QueryHostFile( IN OUT PQUERY_BLOB pBlob ) /*++
Routine Description:
Lookup query in host file.
Arguments:
Return Value:
TRUE if found host file entry. FALSE otherwise.
--*/ { HOST_FILE_INFO hostInfo; BOOL fip6 = FALSE; BOOL fptr = FALSE; IP_UNION ipUnion; WORD wtype; WORD buildType; PCHAR pcnameHost = NULL; PDNS_RECORD prrAlias = NULL; PDNS_RECORD prr = NULL; DNS_LIST forwardList; DWORD bufLength; PSTR pnameAnsi = (PCHAR) pBlob->NameBufferWide;
DNSDBG( INIT, ( "QueryHostFile()\n" ));
//
// determine if host file type
//
wtype = pBlob->wType;
if ( wtype == DNS_TYPE_A || wtype == DNS_TYPE_PTR || wtype == DNS_TYPE_ALL ) { // no op
} else if ( wtype == DNS_TYPE_AAAA ) { fip6 = TRUE; } else { return FALSE; }
//
// open hosts file -- if fails, we're done
//
RtlZeroMemory( &hostInfo, sizeof(hostInfo) );
if ( !Dns_OpenHostFile( &hostInfo ) ) { return( FALSE ); }
//
// convert name to ANSI
// - validate and select IP4\IP6 for PTR
//
bufLength = DNS_MAX_NAME_BUFFER_LENGTH;
if ( ! Dns_NameCopy( pnameAnsi, & bufLength, pBlob->pNameWire, 0, DnsCharSetWire, DnsCharSetAnsi ) ) { goto Cleanup; }
//
// reverse name check
// - validate and select IP 4\6
// - PTR lookup MUST be valid reverse name
// - ALL may be reverse name
//
if ( wtype == DNS_TYPE_PTR || wtype == DNS_TYPE_ALL ) { DWORD bufferLength = sizeof(IP6_ADDRESS); BOOL family = 0;
if ( Dns_ReverseNameToAddress_A( (PCHAR) & ipUnion.Addr, & bufferLength, pnameAnsi, & family // either address type
) ) { fptr = TRUE; ipUnion.IsIp6 = (family == AF_INET6); } else if ( wtype == DNS_TYPE_PTR ) { // bad reverse name
goto Cleanup; } }
//
// forward build type
// - matches query type
// - EXCEPT all which currently builds
// AAAA for IP6, A for IP4
//
if ( !fptr ) { buildType = wtype; DNS_LIST_STRUCT_INIT( forwardList ); }
//
// read entries from host file until exhausted
// - cache A record for each name and alias
// - cache PTR to name
//
while ( Dns_ReadHostFileLine( &hostInfo ) ) { //
// reverse
// - match IP
// - success is terminal as reverse mapping is one-to-one
//
// DCR_QUESTION: parse hosts for multiple reverse mappings?
//
if ( fptr ) { // DCR: extract as genericIP comparison
if ( ! Dns_EqualIpUnion( &ipUnion, &hostInfo.Ip ) ) { continue; }
// create RR
// - don't need to use IP conversion version
// as we already have reverse lookup name
DNSDBG( QUERY, ( "Build PTR record for name %s to %s\n", pnameAnsi, hostInfo.pHostName ));
prr = Dns_CreatePtrTypeRecord( pnameAnsi, TRUE, // copy name
hostInfo.pHostName, DNS_TYPE_PTR, HOSTFILE_RECORD_TTL, DnsCharSetAnsi, DnsCharSetUnicode );
if ( !prr ) { SetLastError( DNS_ERROR_NO_MEMORY ); } break; }
//
// forward lookup
//
else { PCHAR pnameHost;
// type ALL builds on any match
// - build type appropriate for IP
//
// other query types must match address type
if ( wtype == DNS_TYPE_ALL ) { buildType = IPUNION_IS_IP6(&hostInfo.Ip) ? DNS_TYPE_AAAA : DNS_TYPE_A; } else if ( fip6 != IPUNION_IS_IP6(&hostInfo.Ip) ) { continue; }
//
// check name match
//
// DCR: use unicode name? or UTF8 name directly
pnameHost = NULL;
if ( Dns_NameCompare_A( hostInfo.pHostName, pnameAnsi ) ) { pnameHost = pnameAnsi; }
//
// check match to previous CNAME
//
else if ( pcnameHost ) { if ( Dns_NameCompare_A( hostInfo.pHostName, pcnameHost ) ) { pnameHost = pcnameHost; } }
//
// aliases
//
// DCR_QUESTION: build aliases even if name hit?
//
// currently:
// - don't allow alias if already have direct record
// - limit to one alias (CNAME)
//
// if find alias:
// - build CNAME record
// - save CNAME target (in ANSI for faster compares)
// - check CNAME target for subsequent address records (above)
//
else if ( IS_DNS_LIST_STRUCT_EMPTY( forwardList ) && !prrAlias ) { PCHAR * paliasEntry; PCHAR palias;
for( paliasEntry = hostInfo.AliasArray; palias = *paliasEntry; paliasEntry++ ) { if ( Dns_NameCompare_A( palias, pnameAnsi ) ) { DNSDBG( QUERY, ( "Build CNAME record for name %s to CNAME %s\n", pnameAnsi, hostInfo.pHostName ));
prrAlias = Dns_CreatePtrTypeRecord( pnameAnsi, TRUE, // copy name
hostInfo.pHostName, DNS_TYPE_CNAME, HOSTFILE_RECORD_TTL, DnsCharSetAnsi, DnsCharSetUnicode ); if ( prrAlias ) { pcnameHost = Dns_NameCopyAllocate( hostInfo.pHostName, 0, DnsCharSetAnsi, DnsCharSetAnsi );
pnameHost = pcnameHost; } break; } } }
// add address record for this hostline
if ( pnameHost ) { DNSDBG( QUERY, ( "Build address record for name %s\n", pnameHost ));
prr = Dns_CreateForwardRecord( pnameHost, & hostInfo.Ip, HOSTFILE_RECORD_TTL, DnsCharSetAnsi, DnsCharSetUnicode ); if ( prr ) { DNS_LIST_STRUCT_ADD( forwardList, prr ); } } } }
//
// build response
//
// DCR: new multiple section response
//
if ( !fptr ) { prr = forwardList.pFirst; if ( prrAlias ) { prrAlias->pNext = prr; prr = prrAlias; } }
IF_DNSDBG( QUERY ) { DnsDbg_RecordSet( "HostFile Answers:", prr ); } pBlob->pRecords = prr;
Cleanup:
//
// cleanup
//
Dns_CloseHostFile( &hostInfo );
if ( pcnameHost ) { FREE_HEAP( pcnameHost ); }
DNSDBG( TRACE, ( "Leave QueryHostFile() -> %d\n" "\tprr = %p\n", prr ? TRUE : FALSE, prr ));
return( prr ? TRUE : FALSE ); }
//
// End hostfile.c
//
|