Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

941 lines
20 KiB

/*++
Copyright (c) 2000-2002 Microsoft Corporation
Module Name:
localip.c
Abstract:
Local IP address routines.
Author:
Jim Gilroy October 2000
Revision History:
--*/
#include "local.h"
//
// TTL on local records
//
// Use registration TTL
//
#define LOCAL_IP_TTL (g_RegistrationTtl)
//
// Test locality.
//
BOOL
LocalIp_IsAddrLocal(
IN PDNS_ADDR pAddr,
IN PDNS_ADDR_ARRAY pLocalArray, OPTIONAL
IN PDNS_NETINFO pNetInfo OPTIONAL
)
/*++
Routine Description:
Determine if IP is local.
Arguments:
pAddr -- ptr to IP to test
pLocalArray -- local addresses to check
pNetInfo -- network info to check
Return Value:
TRUE if local IP
FALSE if remote
--*/
{
BOOL bresult = FALSE;
PADDR_ARRAY parray;
//
// test for loopback
//
if ( DnsAddr_IsLoopback(
pAddr,
0 // any family
) )
{
return TRUE;
}
//
// test against local addrs
// - use addr list if provided
// - use netinfo if provided
// - otherwise query to get it
//
parray = pLocalArray;
if ( !parray )
{
parray = NetInfo_GetLocalAddrArray(
pNetInfo,
NULL, // no specific adapter
0, // no specific family
0, // no flags
FALSE // no force
);
}
bresult = DnsAddrArray_ContainsAddr(
parray,
pAddr,
DNSADDR_MATCH_IP );
if ( parray != pLocalArray )
{
DnsAddrArray_Free( parray );
}
return bresult;
}
//
// Local address list
//
BOOL
local_ScreenLocalAddrNotCluster(
IN PDNS_ADDR pAddr,
IN PDNS_ADDR pScreenAddr OPTIONAL
)
/*++
Routine Description:
Screen cluster out of local addrs.
This is DnsAddrArray_ContainsAddrEx() screening function
for use by GetLocalPtrRecord() to avoid matching cluster
addresses.
Arguments:
pAddr -- address to screen
pScreenAddr -- screening info; ignored for this function
Return Value:
TRUE if local addr passes screen -- is not cluster IP.
FALSE if cluster.
--*/
{
// screen flags
// - exact match on address type flag bits
return ( !(pAddr->Flags & DNSADDR_FLAG_TRANSIENT) );
}
PDNS_RECORD
local_GetLocalPtrRecord(
IN OUT PQUERY_BLOB pBlob
)
/*++
Routine Description:
Get pointer record for local IP.
Arguments:
pBlob -- query blob
Uses:
pNameOrig
wType
pNetInfo
Sets:
NameBufferWide -- used as local storage
Return Value:
Ptr to record for query, if query name\type is IP.
NULL if query not for IP.
--*/
{
DNS_ADDR addr;
PDNS_ADDR paddr = &addr;
PDNS_RECORD prr;
PWSTR pnameHost = NULL;
PWSTR pnameDomain;
PDNS_ADAPTER padapter = NULL;
DWORD iter;
PWSTR pnameQuery = pBlob->pNameOrig;
PDNS_NETINFO pnetInfo = pBlob->pNetInfo;
DNSDBG( TRACE, (
"\nlocal_GetLocalPtrRecord( %S )\n",
pnameQuery ));
if ( !pnameQuery )
{
return NULL;
}
//
// convert reverse name to IP
//
if ( ! Dns_ReverseNameToDnsAddr_W(
paddr,
pnameQuery ) )
{
DNSDBG( ANY, (
"WARNING: Ptr lookup name %S is not reverse name!\n",
pnameQuery ));
return NULL;
}
//
// check for generic IP match
// - skip for mcast response
// - accept loopback or any on normal query
//
if ( !(pBlob->Flags & DNSP_QUERY_NO_GENERIC_NAMES) )
{
if ( DnsAddr_IsLoopback( paddr, 0 ) )
{
DNSDBG( QUERY, (
"Local PTR lookup matched loopback.\n" ));
goto Matched;
}
else if ( DnsAddr_IsUnspec( paddr, 0 ) )
{
DNSDBG( QUERY, (
"Local PTR lookup matched unspec.\n" ));
goto Matched;
}
}
//
// check for specific IP match
//
NetInfo_AdapterLoopStart( pnetInfo );
while( padapter = NetInfo_GetNextAdapter( pnetInfo ) )
{
//
// have address match?
// if server must use screening function to skip cluster IPs
//
// note: cluster IPs will be mapped back to virtual cluster
// name by cache
if ( DnsAddrArray_ContainsAddrEx(
padapter->pLocalAddrs,
paddr,
DNSADDR_MATCH_IP,
g_IsServer
? local_ScreenLocalAddrNotCluster
: NULL,
NULL // no screen address required
) )
{
goto Matched;
}
}
//
// no IP match
//
DNSDBG( QUERY, (
"Leave local PTR lookup. No local IP match.\n"
"\treverse name = %S\n",
pnameQuery ));
return NULL;
Matched:
//
// create hostname
// preference order:
// - full PDN
// - full adapter domain name from adapter with IP
// - hostname (single label)
// - "localhost"
//
{
PWCHAR pnameBuf = pBlob->NameBuffer;
pnameHost = pnetInfo->pszHostName;
if ( !pnameHost )
{
pnameHost = L"localhost";
goto Build;
}
pnameDomain = pnetInfo->pszDomainName;
if ( !pnameDomain )
{
// use the adapter name even if NOT set for registration
// if ( !padapter ||
// !(padapter->InfoFlags & AINFO_FLAG_REGISTER_DOMAIN_NAME) )
if ( !padapter )
{
goto Build;
}
pnameDomain = padapter->pszAdapterDomain;
if ( !pnameDomain )
{
goto Build;
}
}
if ( ! Dns_NameAppend_W(
pnameBuf,
DNS_MAX_NAME_BUFFER_LENGTH,
pnameHost,
pnameDomain ) )
{
DNS_ASSERT( FALSE );
goto Build;
}
pnameHost = pnameBuf;
Build:
//
// create record
//
prr = Dns_CreatePtrRecordEx(
paddr,
(PDNS_NAME) pnameHost,
LOCAL_IP_TTL,
DnsCharSetUnicode,
DnsCharSetUnicode );
if ( !prr )
{
DNSDBG( ANY, (
"Local PTR record creation failed for name %S!\n",
pnameHost ));
return NULL;
}
}
DNSDBG( QUERY, (
"Created local PTR record %p with hostname %S.\n"
"\treverse name = %S\n",
prr,
pnameHost,
pnameQuery ));
return prr;
}
VOID
localip_BuildRRListFromArray(
IN OUT PDNS_RRSET pRRSet,
IN PWSTR pNameRecord,
IN WORD wType,
IN PDNS_ADDR_ARRAY pAddrArray
)
/*++
Routine Description:
Build address record lists for local IP.
Helper function as this same logic is in multiple places
due to the tedious way we must put this together.
Arguments:
Return Value:
--*/
{
DWORD jter;
PDNS_RECORD prr;
INT fpass;
DNSDBG( TRACE, (
"localip_BuildRRListFromArray()\n"
"\tpname = %S\n"
"\twtype = %d\n"
"\tparray = %p\n",
pNameRecord,
wType,
pAddrArray ));
//
// validate array
//
if ( !pAddrArray )
{
DNSDBG( QUERY, (
"No addrs for record build -- NULL array!!!\n" ));
return;
}
//
// loop through adapter addresses
//
if ( pRRSet->pFirstRR != NULL )
{
pNameRecord = NULL;
}
for ( jter = 0;
jter < pAddrArray->AddrCount;
jter++ )
{
prr = Dns_CreateForwardRecord(
pNameRecord,
wType,
&pAddrArray->AddrArray[jter],
LOCAL_IP_TTL,
DnsCharSetUnicode,
DnsCharSetUnicode );
if ( prr )
{
DNS_RRSET_ADD( *pRRSet, prr );
pNameRecord = NULL;
}
}
}
PDNS_RECORD
local_GetLocalAddressRecord(
IN OUT PQUERY_BLOB pBlob
)
/*++
Routine Description:
Get address record for local IP.
Arguments:
pBlob -- query blob
Uses:
pNameOrig
wType
pNetInfo
fNoGenericNames
Sets:
fNoIpLocal
TRUE -- no IP of type found, defaulted record
FALSE -- records valid
NameBuffer -- used as local storage
fGenericNames -- accept local generic names (NULL, loopback, localhost)
TRUE for DnsQuery() path
FALSE for mcast queries
Return Value:
Ptr to record for query, if query name\type is IP.
NULL if query not for IP.
--*/
{
DNS_ADDR addr;
IP4_ADDRESS ip4;
IP6_ADDRESS ip6;
PDNS_ADDR_ARRAY parray = NULL;
DWORD addrFlag;
DWORD family;
PDNS_RECORD prr;
BOOL fmatchedName = FALSE;
PWSTR pnameRecord = NULL;
DWORD iter;
DWORD bufLength;
PWSTR pnameDomain;
DNS_RRSET rrset;
WORD wtype = pBlob->wType;
PWSTR pnameBuf = pBlob->NameBuffer;
PWSTR pnameQuery = pBlob->pNameOrig;
PDNS_NETINFO pnetInfo = pBlob->pNetInfo;
PDNS_ADAPTER padapter;
DNSDBG( TRACE, (
"local_GetLocalAddressRecord( %S, %d )\n",
pnameQuery,
wtype ));
// clear out param
pBlob->fNoIpLocal = FALSE;
// address types to include
addrFlag = DNS_CONFIG_FLAG_ADDR_NON_CLUSTER;
family = Family_GetFromDnsType( wtype );
if ( !family )
{
DNS_ASSERT( FALSE );
return NULL;
}
// init record builder
DNS_RRSET_INIT( rrset );
//
// generic local names
// - skip for doing MCAST matching
// - NULL, empty, loopback, localhost accepted for regular query
//
if ( pBlob->Flags & DNSP_QUERY_NO_GENERIC_NAMES )
{
if ( !pnameQuery )
{
return NULL;
}
}
else
{
//
// NULL treated as local PDN
//
if ( !pnameQuery || !*pnameQuery )
{
DNSDBG( QUERY, ( "Local lookup -- no query name, treat as PDN.\n" ));
goto MatchedPdn;
}
//
// "*" treated as all machine records
//
if ( Dns_NameCompare_W(
pnameQuery,
L"..localmachine" ) )
{
DNSDBG( QUERY, ( "Local lookup -- * query name.\n" ));
addrFlag |= DNS_CONFIG_FLAG_ADDR_CLUSTER;
goto MatchedPdn;
}
//
// loopback or localhost
//
if ( Dns_NameCompare_W(
pnameQuery,
L"loopback" )
||
Dns_NameCompare_W(
pnameQuery,
L"localhost" ) )
{
pnameRecord = pnameQuery,
IP6_SET_ADDR_LOOPBACK( &ip6 );
ip4 = DNS_NET_ORDER_LOOPBACK;
goto SingleIp;
}
}
//
// if no hostname -- done
//
if ( !pnetInfo->pszHostName )
{
DNSDBG( QUERY, ( "No hostname configured!\n" ));
return NULL;
}
//
// copy name
//
if ( ! Dns_NameCopyStandard_W(
pnameBuf,
pBlob->pNameOrig ) )
{
DNSDBG( ANY, (
"Invalid name %S to local address query.\n",
pnameQuery ));
return NULL;
}
// split query name into hostname and domain name
pnameDomain = Dns_SplitHostFromDomainNameW( pnameBuf );
// must have hostname match
if ( !Dns_NameCompare_W(
pnameBuf,
pnetInfo->pszHostName ) )
{
DNSDBG( ANY, (
"Local lookup, failed hostname match!\n",
pnameQuery ));
return NULL;
}
//
// hostname's match
// - no domain name => PDN equivalent
// - match PDN => all addresses
// - match adapter name => adapter addresses
// - no match
//
// check PDN match
if ( !pnameDomain )
{
DNSDBG( QUERY, ( "Local lookup -- no domain, treat as PDN!\n" ));
goto MatchedPdn;
}
if ( Dns_NameCompare_W(
pnameDomain,
pnetInfo->pszDomainName ) )
{
DNSDBG( QUERY, ( "Local lookup -- matched PDN!\n" ));
goto MatchedPdn;
}
//
// NO PDN match -- check adapter name match
//
for ( iter=0; iter<pnetInfo->AdapterCount; iter++ )
{
padapter = NetInfo_GetAdapterByIndex( pnetInfo, iter );
if ( !(padapter->InfoFlags & AINFO_FLAG_REGISTER_DOMAIN_NAME) ||
! padapter->pLocalAddrs ||
! Dns_NameCompare_W(
pnameDomain,
padapter->pszAdapterDomain ) )
{
continue;
}
// build name if we haven't built it before
// we stay in the loop in case more than one
// adapter has the same domain name
if ( !fmatchedName )
{
DNSDBG( QUERY, (
"Local lookup -- matched adapter name %S\n",
padapter->pszAdapterDomain ));
if ( ! Dns_NameAppend_W(
pnameBuf,
DNS_MAX_NAME_BUFFER_LENGTH,
pnetInfo->pszHostName,
padapter->pszAdapterDomain ) )
{
DNS_ASSERT( FALSE );
return NULL;
}
pnameRecord = pnameBuf;
fmatchedName = TRUE;
}
//
// build forward records for all IPs in adapter
//
// note: we do NOT include cluster addrs for adapter name match
// as we only must be able to provide in the
// gethostbyname(NULL) type cases, which use PDN
//
// DCR: mem alloc failures building local records
// getting no records built mapped properly to NO_MEMORY error
//
parray = NetInfo_CreateLocalAddrArray(
pnetInfo,
NULL, // no adapter name
padapter, // just this adapter
family,
addrFlag );
if ( !parray )
{
continue;
}
localip_BuildRRListFromArray(
&rrset,
pnameRecord,
wtype,
parray
);
DnsAddrArray_Free( parray );
parray = NULL;
}
//
// done with adapter name match
// either
// - no match
// - match but didn't get IPs
// - match
if ( !fmatchedName )
{
DNSDBG( QUERY, (
"Leave local_GetLocalAddressRecord() => no domain name match.\n" ));
return NULL;
}
prr = rrset.pFirstRR;
if ( prr )
{
DNSDBG( QUERY, (
"Leave local_GetLocalAddressRecord() => %p matched adapter name.\n",
prr ));
return prr;
}
goto NoIp;
MatchedPdn:
//
// matched PDN
//
// for gethostbyname() app-compat, must build in specific order
// - first IP in each adapter
// - remainder of IPs on adapters
//
if ( pnetInfo->pszHostName )
{
if ( ! Dns_NameAppend_W(
pnameBuf,
DNS_MAX_NAME_BUFFER_LENGTH,
pnetInfo->pszHostName,
pnetInfo->pszDomainName ) )
{
DNS_ASSERT( FALSE );
return NULL;
}
pnameRecord = pnameBuf;
}
else
{
pnameRecord = L"localhost";
}
//
// read addrs
//
// note: we don't add cluster flag above, as cluster addrs
// not used on adapter name matches, just PDN for gethostbyname()
// compat
//
if ( g_IsServer &&
(pBlob->Flags & DNSP_QUERY_INCLUDE_CLUSTER) )
{
addrFlag |= DNS_CONFIG_FLAG_ADDR_CLUSTER;
}
// DCR: mem alloc failures building local records
// getting no records built mapped properly to NO_MEMORY error
//
parray = NetInfo_CreateLocalAddrArray(
pnetInfo,
NULL, // no adapter name
NULL, // no specific adatper
family,
addrFlag );
if ( !parray )
{
return NULL;
}
localip_BuildRRListFromArray(
&rrset,
pnameRecord,
wtype,
parray
);
DnsAddrArray_Free( parray );
// if successfully built -- done
prr = rrset.pFirstRR;
if ( prr )
{
DNSDBG( QUERY, (
"Leave local_GetLocalAddressRecord() => %p matched PDN name.\n",
prr ));
return prr;
}
// matched name but found no records
// fall through to NoIp section
//
//goto NoIp;
NoIp:
//
// matched name -- but no IP
// use loopback address; assume this is a lookup prior to
// connect which happens to be the local name, rather than an
// explict local lookup to get binding IPs
//
DNSDBG( ANY, (
"WARNING: local name match but no IP -- using loopback\n" ));
IP6_SET_ADDR_LOOPBACK( &ip6 );
ip4 = DNS_NET_ORDER_LOOPBACK;
pBlob->fNoIpLocal = TRUE;
// fall through to single IP
SingleIp:
// single IP
// - loopback address and be unicode queried name
if ( wtype == DNS_TYPE_A )
{
DnsAddr_BuildFromIp4(
&addr,
ip4,
0 // no port
);
}
else
{
DnsAddr_BuildFromIp6(
&addr,
& ip6,
0, // no scope
0 // no port
);
}
prr = Dns_CreateForwardRecord(
(PDNS_NAME) pnameRecord,
wtype,
& addr,
LOCAL_IP_TTL,
DnsCharSetUnicode,
DnsCharSetUnicode );
return prr;
}
DNS_STATUS
Local_GetRecordsForLocalName(
IN OUT PQUERY_BLOB pBlob
)
/*++
Routine Description:
Get local address info array.
EXPORTED: called by resolver for MCAST
Arguments:
pBlob -- query blob
Uses:
pNameOrig
wType
pNetInfo
Sets:
pLocalRecords
fNoIpLocal if local name without records
Return Value:
ERROR_SUCCESS if successful.
DNS_ERROR_RCODE_NAME_ERROR on failure.
--*/
{
WORD wtype = pBlob->wType;
PDNS_RECORD prr = NULL;
if ( wtype == DNS_TYPE_A ||
wtype == DNS_TYPE_AAAA )
{
prr = local_GetLocalAddressRecord( pBlob );
}
else if ( wtype == DNS_TYPE_PTR )
{
prr = local_GetLocalPtrRecord( pBlob );
}
// set local records
// - if not NO IP situation then this
// is final query result also
if ( prr )
{
pBlob->pLocalRecords = prr;
if ( !pBlob->fNoIpLocal )
{
pBlob->pRecords = prr;
}
return ERROR_SUCCESS;
}
return DNS_ERROR_RCODE_NAME_ERROR;
}
//
// End localip.c
//