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.
2845 lines
59 KiB
2845 lines
59 KiB
/*++
|
|
|
|
Copyright (c) 2000-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
hostent.c
|
|
|
|
Abstract:
|
|
|
|
Domain Name System (DNS) Library
|
|
|
|
Hostent routines.
|
|
|
|
Author:
|
|
|
|
Jim Gilroy (jamesg) December 4, 2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "local.h"
|
|
#include "ws2atm.h" // ATM address
|
|
|
|
|
|
//
|
|
// Max number of aliases
|
|
//
|
|
|
|
#define DNS_MAX_ALIAS_COUNT (8)
|
|
|
|
//
|
|
// Min size of hostent address buffer
|
|
// - enough for one address of largest type
|
|
//
|
|
|
|
#define MIN_ADDR_BUF_SIZE (sizeof(ATM_ADDRESS))
|
|
|
|
|
|
//
|
|
// String alignment in buffer
|
|
//
|
|
// DCR: string buffer alignment exposed globally
|
|
//
|
|
// Since address and string DATA (not ptrs) can be intermixed
|
|
// as we build, we MUST size strings for DWORD (at minimum) so
|
|
// to that addresses may be DWORD aligned.
|
|
// However, when we build we can pack as tightly as desired
|
|
// though obviously unicode strings must WCHAR align.
|
|
//
|
|
|
|
#define HOSTENT_STRING_ALIGN_DWORD(size) DWORD_ALIGN_DWORD(size)
|
|
#define HOSTENT_STRING_ALIGN_PTR(ptr) DWORD_ALIGN(ptr)
|
|
|
|
#define REQUIRED_HOSTENT_STRING_ALIGN_DWORD(size) WORD_ALIGN_DWORD(size)
|
|
#define REQUIRED_HOSTENT_STRING_ALIGN_PTR(ptr) WORD_ALIGN(ptr)
|
|
|
|
|
|
//
|
|
// Hostent utilities
|
|
//
|
|
|
|
|
|
BOOL
|
|
Hostent_IsSupportedAddrType(
|
|
IN WORD wType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Is this a supported address type for hostent.
|
|
|
|
Arguments:
|
|
|
|
wType -- type in question
|
|
|
|
Return Value:
|
|
|
|
TRUE if type supported
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
return ( wType == DNS_TYPE_A ||
|
|
wType == DNS_TYPE_AAAA ||
|
|
wType == DNS_TYPE_ATMA );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
Hostent_Size(
|
|
IN PHOSTENT pHostent,
|
|
IN DNS_CHARSET CharSetExisting,
|
|
IN DNS_CHARSET CharSetTarget,
|
|
IN PDWORD pAliasCount,
|
|
IN PDWORD pAddrCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find size of hostent.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- hostent
|
|
|
|
CharSetExisting -- char set of pHostent
|
|
|
|
CharSetTarget -- char set to size to
|
|
|
|
pAliasCount -- count of aliases
|
|
|
|
pAddrCount -- count of addrs
|
|
|
|
Return Value:
|
|
|
|
Size in bytes of hostent.
|
|
|
|
--*/
|
|
{
|
|
DWORD sizeName = 0;
|
|
DWORD sizeAliasNames = 0;
|
|
DWORD sizeAliasPtr;
|
|
DWORD sizeAddrPtr;
|
|
DWORD sizeAddrs;
|
|
DWORD sizeTotal;
|
|
PCHAR palias;
|
|
DWORD addrCount = 0;
|
|
DWORD aliasCount = 0;
|
|
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Hostent_Size( %p, %d, %d )\n",
|
|
pHostent,
|
|
CharSetExisting,
|
|
CharSetTarget ));
|
|
|
|
//
|
|
// name
|
|
//
|
|
|
|
if ( pHostent->h_name )
|
|
{
|
|
sizeName = Dns_GetBufferLengthForStringCopy(
|
|
pHostent->h_name,
|
|
0,
|
|
CharSetExisting,
|
|
CharSetTarget );
|
|
|
|
sizeName = HOSTENT_STRING_ALIGN_DWORD( sizeName );
|
|
}
|
|
|
|
//
|
|
// aliases
|
|
//
|
|
|
|
if ( pHostent->h_aliases )
|
|
{
|
|
while ( palias = pHostent->h_aliases[aliasCount] )
|
|
{
|
|
sizeAliasNames += Dns_GetBufferLengthForStringCopy(
|
|
palias,
|
|
0,
|
|
CharSetExisting,
|
|
CharSetTarget );
|
|
|
|
sizeAliasNames = HOSTENT_STRING_ALIGN_DWORD( sizeAliasNames );
|
|
aliasCount++;
|
|
}
|
|
}
|
|
sizeAliasPtr = (aliasCount+1) * sizeof(PCHAR);
|
|
|
|
//
|
|
// addresses
|
|
//
|
|
|
|
if ( pHostent->h_addr_list )
|
|
{
|
|
while ( pHostent->h_addr_list[addrCount] )
|
|
{
|
|
addrCount++;
|
|
}
|
|
}
|
|
sizeAddrPtr = (addrCount+1) * sizeof(PCHAR);
|
|
sizeAddrs = addrCount * pHostent->h_length;
|
|
|
|
//
|
|
// calc total size
|
|
//
|
|
// note: be careful of alignment issues
|
|
// our layout is
|
|
// - hostent struct
|
|
// - ptr arrays
|
|
// - address + string data
|
|
//
|
|
// since address and string DATA (not ptrs) can be intermixed
|
|
// as we build, we MUST size strings for DWORD (at minimum) so
|
|
// to that addresses may be DWORD aligned
|
|
//
|
|
// in copying we can copy all addresses first and avoid intermix
|
|
// but DWORD string alignment is still safe
|
|
//
|
|
|
|
sizeTotal = POINTER_ALIGN_DWORD( sizeof(HOSTENT) ) +
|
|
sizeAliasPtr +
|
|
sizeAddrPtr +
|
|
sizeAddrs +
|
|
sizeName +
|
|
sizeAliasNames;
|
|
|
|
if ( pAddrCount )
|
|
{
|
|
*pAddrCount = addrCount;
|
|
}
|
|
if ( pAliasCount )
|
|
{
|
|
*pAliasCount = aliasCount;
|
|
}
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Hostent sized:\n"
|
|
"\tname = %d\n"
|
|
"\talias ptrs = %d\n"
|
|
"\talias names = %d\n"
|
|
"\taddr ptrs = %d\n"
|
|
"\taddrs = %d\n"
|
|
"\ttotal = %d\n",
|
|
sizeName,
|
|
sizeAliasPtr,
|
|
sizeAliasNames,
|
|
sizeAddrPtr,
|
|
sizeAddrs,
|
|
sizeTotal ));
|
|
|
|
return sizeTotal;
|
|
}
|
|
|
|
|
|
|
|
PHOSTENT
|
|
Hostent_Init(
|
|
IN OUT PBYTE * ppBuffer,
|
|
//IN OUT PINT pBufSize,
|
|
IN INT Family,
|
|
IN INT AddrLength,
|
|
IN DWORD AddrCount,
|
|
IN DWORD AliasCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Init hostent struct.
|
|
|
|
Assumes length is adequate.
|
|
|
|
Arguments:
|
|
|
|
ppBuffer -- addr to ptr to buffer to write hostent;
|
|
on return contains next location in buffer
|
|
|
|
Family -- address family
|
|
|
|
AddrLength -- address length
|
|
|
|
AddrCount -- address count
|
|
|
|
AliasCount -- alias count
|
|
|
|
Return Value:
|
|
|
|
Ptr to hostent.
|
|
|
|
--*/
|
|
{
|
|
PBYTE pbuf = *ppBuffer;
|
|
PHOSTENT phost;
|
|
DWORD size;
|
|
|
|
//
|
|
// hostent
|
|
// - must be pointer aligned
|
|
//
|
|
|
|
phost = (PHOSTENT) POINTER_ALIGN( pbuf );
|
|
|
|
phost->h_name = NULL;
|
|
phost->h_length = (SHORT) AddrLength;
|
|
phost->h_addrtype = (SHORT) Family;
|
|
|
|
pbuf = (PBYTE) (phost + 1);
|
|
|
|
//
|
|
// init alias array
|
|
// - set hostent ptr
|
|
// - clear entire alias array;
|
|
// since this count is often defaulted nice to clear it just
|
|
// to avoid junk
|
|
//
|
|
|
|
pbuf = (PBYTE) POINTER_ALIGN( pbuf );
|
|
phost->h_aliases = (PCHAR *) pbuf;
|
|
|
|
size = (AliasCount+1) * sizeof(PCHAR);
|
|
|
|
RtlZeroMemory(
|
|
pbuf,
|
|
size );
|
|
|
|
pbuf += size;
|
|
|
|
//
|
|
// init addr array
|
|
// - set hostent ptr
|
|
// - clear first address entry
|
|
// callers responsibility to NULL last addr pointer when done
|
|
//
|
|
|
|
*(PCHAR *)pbuf = NULL;
|
|
phost->h_addr_list = (PCHAR *) pbuf;
|
|
|
|
pbuf += (AddrCount+1) * sizeof(PCHAR);
|
|
|
|
//
|
|
// return next position in buffer
|
|
//
|
|
|
|
*ppBuffer = pbuf;
|
|
|
|
return phost;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
Dns_PtrArrayToOffsetArray(
|
|
IN OUT PCHAR * PtrArray,
|
|
IN PCHAR pBase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Change an array of pointers into array of offsets.
|
|
|
|
This is used to convert aliases lists to offsets.
|
|
|
|
Arguments:
|
|
|
|
pPtrArray -- addr of ptr to array of pointers to convert to offsets
|
|
the array must be terminated by NULL ptr
|
|
|
|
pBase -- base address to offset from
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PCHAR * pptr = PtrArray;
|
|
PCHAR pdata;
|
|
|
|
DNSDBG( TRACE, ( "Dns_PtrArrayToOffsetArray()\n" ));
|
|
|
|
//
|
|
// turn each pointer into offset
|
|
//
|
|
|
|
while( pdata = *pptr )
|
|
{
|
|
*pptr++ = (PCHAR)( (PCHAR)pdata - (PCHAR)pBase );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
Hostent_ConvertToOffsets(
|
|
IN OUT PHOSTENT pHostent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert hostent to offsets.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- hostent to convert to offsets
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PBYTE ptr;
|
|
|
|
DNSDBG( TRACE, ( "Hostent_ConvertToOffsets()\n" ));
|
|
|
|
//
|
|
// convert
|
|
// - name
|
|
// - alias array pointer
|
|
// - address array pointer
|
|
//
|
|
|
|
if ( ptr = pHostent->h_name )
|
|
{
|
|
pHostent->h_name = (PCHAR) (ptr - (PBYTE)pHostent);
|
|
}
|
|
|
|
// alias array
|
|
// - convert array pointer
|
|
// - convert pointers in array
|
|
|
|
if ( ptr = (PBYTE)pHostent->h_aliases )
|
|
{
|
|
pHostent->h_aliases = (PCHAR *) (ptr - (PBYTE)pHostent);
|
|
|
|
Dns_PtrArrayToOffsetArray(
|
|
(PCHAR *) ptr,
|
|
(PCHAR) pHostent );
|
|
}
|
|
|
|
// address array
|
|
// - convert array pointer
|
|
// - convert pointers in array
|
|
|
|
if ( ptr = (PBYTE)pHostent->h_addr_list )
|
|
{
|
|
pHostent->h_addr_list = (PCHAR *) (ptr - (PBYTE)pHostent);
|
|
|
|
Dns_PtrArrayToOffsetArray(
|
|
(PCHAR *) ptr,
|
|
(PCHAR) pHostent );
|
|
}
|
|
|
|
DNSDBG( TRACE, ( "Leave Hostent_ConvertToOffsets()\n" ));
|
|
}
|
|
|
|
|
|
|
|
PHOSTENT
|
|
Hostent_Copy(
|
|
IN OUT PBYTE * ppBuffer,
|
|
IN OUT PINT pBufferSize,
|
|
OUT PINT pHostentSize,
|
|
IN PHOSTENT pHostent,
|
|
IN DNS_CHARSET CharSetIn,
|
|
IN DNS_CHARSET CharSetTarget,
|
|
IN BOOL fOffsets,
|
|
IN BOOL fAlloc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Copy a hostent.
|
|
|
|
Arguments:
|
|
|
|
ppBuffer -- addr with ptr to buffer to write to;
|
|
if no buffer then hostent is allocated
|
|
updated with ptr to position in buffer after hostent
|
|
|
|
pBufferSize -- addr containing size of buffer;
|
|
updated with bytes left after hostent written
|
|
(even if out of space, it contains missing number of
|
|
bytes as negative number)
|
|
|
|
pHostentSize -- addr to recv total size of hostent written
|
|
|
|
pHostent -- existing hostent to copy
|
|
|
|
CharSetIn -- charset of existing hostent
|
|
|
|
CharSetTarget -- charset of target hostent
|
|
|
|
fOffsets -- write hostent with offsets
|
|
|
|
fAlloc -- allocate copy
|
|
|
|
Return Value:
|
|
|
|
Ptr to new hostent.
|
|
NULL on error. See GetLastError().
|
|
|
|
--*/
|
|
{
|
|
PBYTE pch;
|
|
PHOSTENT phost = NULL;
|
|
DWORD size;
|
|
DWORD sizeTotal;
|
|
DWORD bytesLeft;
|
|
DWORD aliasCount;
|
|
DWORD addrCount;
|
|
DWORD addrLength;
|
|
PCHAR * pptrArrayIn;
|
|
PCHAR * pptrArrayOut;
|
|
PCHAR pdataIn;
|
|
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Hostent_Copy()\n" ));
|
|
|
|
//
|
|
// determine required hostent size
|
|
// - allow sizing skip for already allocated buffers only
|
|
//
|
|
|
|
sizeTotal = Hostent_Size(
|
|
pHostent,
|
|
CharSetIn,
|
|
CharSetTarget,
|
|
& aliasCount,
|
|
& addrCount );
|
|
|
|
//
|
|
// alloc or reserve size in buffer
|
|
//
|
|
|
|
if ( fAlloc )
|
|
{
|
|
pch = ALLOCATE_HEAP( sizeTotal );
|
|
if ( !pch )
|
|
{
|
|
goto Failed;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pch = FlatBuf_Arg_ReserveAlignPointer(
|
|
ppBuffer,
|
|
pBufferSize,
|
|
sizeTotal
|
|
);
|
|
if ( !pch )
|
|
{
|
|
goto Failed;
|
|
}
|
|
}
|
|
|
|
//
|
|
// note: assuming from here on down that we have adequate space
|
|
//
|
|
// reason we aren't building with FlatBuf routines is that
|
|
// a) i wrote this first
|
|
// b) we believe we have adequate space
|
|
// c) i haven't built FlatBuf string conversion routines
|
|
// which we need below (for RnR unicode to ANSI)
|
|
//
|
|
// we could reset buf pointers here and build directly with FlatBuf
|
|
// routines; this isn't directly necessary
|
|
//
|
|
|
|
//
|
|
// init hostent struct
|
|
//
|
|
|
|
addrLength = pHostent->h_length;
|
|
|
|
phost = Hostent_Init(
|
|
& pch,
|
|
pHostent->h_addrtype,
|
|
addrLength,
|
|
addrCount,
|
|
aliasCount );
|
|
|
|
DNS_ASSERT( pch > (PBYTE)phost );
|
|
|
|
//
|
|
// copy addresses
|
|
// - no need to align as previous is address
|
|
//
|
|
|
|
pptrArrayIn = pHostent->h_addr_list;
|
|
pptrArrayOut = phost->h_addr_list;
|
|
|
|
if ( pptrArrayIn )
|
|
{
|
|
while( pdataIn = *pptrArrayIn++ )
|
|
{
|
|
*pptrArrayOut++ = pch;
|
|
|
|
RtlCopyMemory(
|
|
pch,
|
|
pdataIn,
|
|
addrLength );
|
|
|
|
pch += addrLength;
|
|
}
|
|
}
|
|
*pptrArrayOut = NULL;
|
|
|
|
//
|
|
// copy the aliases
|
|
//
|
|
|
|
pptrArrayIn = pHostent->h_aliases;
|
|
pptrArrayOut = phost->h_aliases;
|
|
|
|
if ( pptrArrayIn )
|
|
{
|
|
while( pdataIn = *pptrArrayIn++ )
|
|
{
|
|
pch = REQUIRED_HOSTENT_STRING_ALIGN_PTR( pch );
|
|
|
|
*pptrArrayOut++ = pch;
|
|
|
|
size = Dns_StringCopy(
|
|
pch,
|
|
NULL, // infinite size
|
|
pdataIn,
|
|
0, // unknown length
|
|
CharSetIn,
|
|
CharSetTarget
|
|
);
|
|
pch += size;
|
|
}
|
|
}
|
|
*pptrArrayOut = NULL;
|
|
|
|
//
|
|
// copy the name
|
|
//
|
|
|
|
if ( pHostent->h_name )
|
|
{
|
|
pch = REQUIRED_HOSTENT_STRING_ALIGN_PTR( pch );
|
|
|
|
phost->h_name = pch;
|
|
|
|
size = Dns_StringCopy(
|
|
pch,
|
|
NULL, // infinite size
|
|
pHostent->h_name,
|
|
0, // unknown length
|
|
CharSetIn,
|
|
CharSetTarget
|
|
);
|
|
pch += size;
|
|
}
|
|
|
|
//
|
|
// copy is complete
|
|
// - verify our write functions work
|
|
//
|
|
|
|
ASSERT( (DWORD)(pch-(PBYTE)phost) <= sizeTotal );
|
|
|
|
if ( pHostentSize )
|
|
{
|
|
*pHostentSize = (INT)( pch - (PBYTE)phost );
|
|
}
|
|
|
|
if ( !fAlloc )
|
|
{
|
|
PBYTE pnext = *ppBuffer;
|
|
|
|
// if we sized too small --
|
|
// fix up the buf pointer and bytes left
|
|
|
|
if ( pnext < pch )
|
|
{
|
|
ASSERT( FALSE );
|
|
*ppBuffer = pch;
|
|
*pBufferSize -= (INT)(pch - pnext);
|
|
}
|
|
}
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_Hostent(
|
|
"Hostent copy:",
|
|
phost,
|
|
(CharSetTarget == DnsCharSetUnicode) );
|
|
}
|
|
|
|
//
|
|
// convert to offsets?
|
|
//
|
|
|
|
if ( fOffsets )
|
|
{
|
|
Hostent_ConvertToOffsets( phost );
|
|
}
|
|
|
|
|
|
Failed:
|
|
|
|
DNSDBG( TRACE, (
|
|
"Leave Hostent_Copy() => %p\n",
|
|
phost ));
|
|
|
|
return phost;
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
Hostent_WriteIp4Addrs(
|
|
IN OUT PHOSTENT pHostent,
|
|
OUT PCHAR pAddrBuf,
|
|
IN DWORD MaxBufCount,
|
|
IN PIP4_ADDRESS Ip4Array,
|
|
IN DWORD ArrayCount,
|
|
IN BOOL fScreenZero
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write IP4 addresses to hostent.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- hostent
|
|
|
|
pAddrBuf -- buffer to hold addresses
|
|
|
|
MaxBufCount -- max IPs buffer can hold
|
|
|
|
Ip4Array -- array of IP4 addresses
|
|
|
|
ArrayCount -- array count
|
|
|
|
fScreenZero -- screen out zero addresses?
|
|
|
|
Return Value:
|
|
|
|
Count of addresses written
|
|
|
|
--*/
|
|
{
|
|
DWORD i = 0;
|
|
DWORD stopCount = MaxBufCount;
|
|
PIP4_ADDRESS pip = (PIP4_ADDRESS) pAddrBuf;
|
|
PIP4_ADDRESS * pipPtr = (PIP4_ADDRESS *) pHostent->h_addr_list;
|
|
|
|
//
|
|
// write IP addresses OR loopback if no IPs
|
|
//
|
|
|
|
if ( Ip4Array )
|
|
{
|
|
if ( ArrayCount < stopCount )
|
|
{
|
|
stopCount = ArrayCount;
|
|
}
|
|
|
|
for ( i=0; i < stopCount; ++i )
|
|
{
|
|
IP4_ADDRESS ip = Ip4Array[i];
|
|
if ( ip != 0 || !fScreenZero )
|
|
{
|
|
*pip = ip;
|
|
*pipPtr++ = pip++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pipPtr = NULL;
|
|
|
|
// count of addresses written
|
|
|
|
return( i );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
Hostent_WriteLocalIp4Array(
|
|
IN OUT PHOSTENT pHostent,
|
|
OUT PCHAR pAddrBuf,
|
|
IN DWORD MaxBufCount,
|
|
IN PIP4_ARRAY pIpArray
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write local IP list into hostent.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- hostent
|
|
|
|
pAddrBuf -- buffer to hold addresses
|
|
|
|
MaxBufCount -- max IPs buffer can hold
|
|
|
|
pIpArray -- IP4 array of local addresses
|
|
|
|
Return Value:
|
|
|
|
Count of addresses written
|
|
|
|
--*/
|
|
{
|
|
DWORD count = 0;
|
|
|
|
//
|
|
// write array
|
|
//
|
|
|
|
if ( pIpArray )
|
|
{
|
|
count = Hostent_WriteIp4Addrs(
|
|
pHostent,
|
|
pAddrBuf,
|
|
MaxBufCount,
|
|
pIpArray->AddrArray,
|
|
pIpArray->AddrCount,
|
|
TRUE // screen out zeros
|
|
);
|
|
}
|
|
|
|
//
|
|
// if no addresses written, write loopback
|
|
//
|
|
|
|
if ( count==0 )
|
|
{
|
|
pHostent->h_addr_list[0] = pAddrBuf;
|
|
pHostent->h_addr_list[1] = NULL;
|
|
*((IP4_ADDRESS*)pAddrBuf) = DNS_NET_ORDER_LOOPBACK;
|
|
count = 1;
|
|
}
|
|
|
|
// count of addresses written
|
|
|
|
return( count );
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
Hostent_SetToSingleAddress(
|
|
IN OUT PHOSTENT pHostent,
|
|
IN PCHAR pAddr,
|
|
IN DWORD AddrLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set address in hostent.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- hostent to check
|
|
|
|
pAddr -- ptr to address to check
|
|
|
|
AddrLength -- address length
|
|
|
|
Return Value:
|
|
|
|
TRUE if address successfully copied into hostent.
|
|
FALSE otherwise (no hostent, wrong length, hostent empty)
|
|
|
|
--*/
|
|
{
|
|
PCHAR paddrHostent;
|
|
|
|
//
|
|
// validate
|
|
// - must have hostent
|
|
// - length must match
|
|
//
|
|
|
|
if ( !pHostent ||
|
|
AddrLength != (DWORD)pHostent->h_length )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// slam address in on top of existing
|
|
// - NULL 2nd addr pointer to terminate list
|
|
//
|
|
|
|
paddrHostent = pHostent->h_addr_list[0];
|
|
if ( !paddrHostent )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
paddrHostent,
|
|
pAddr,
|
|
AddrLength );
|
|
|
|
pHostent->h_addr_list[1] = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
Hostent_IsAddressInHostent(
|
|
IN OUT PHOSTENT pHostent,
|
|
IN PCHAR pAddr,
|
|
IN DWORD AddrLength,
|
|
IN INT Family OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does hostent contain this address.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- hostent to check
|
|
|
|
pAddr -- ptr to address to check
|
|
|
|
AddrLength -- address length
|
|
|
|
Family -- address family
|
|
|
|
Return Value:
|
|
|
|
TRUE if address is in hostent.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
BOOL freturn = FALSE;
|
|
DWORD i;
|
|
PCHAR paddrHostent;
|
|
|
|
//
|
|
// validate
|
|
// - must have hostent
|
|
// - must have address
|
|
// - if family given, must match
|
|
// - length must match
|
|
//
|
|
|
|
if ( !pHostent ||
|
|
!pAddr ||
|
|
AddrLength != (DWORD)pHostent->h_length ||
|
|
( Family && Family != pHostent->h_addrtype ) )
|
|
{
|
|
return freturn;
|
|
}
|
|
|
|
//
|
|
// search for address -- if found return TRUE
|
|
//
|
|
|
|
i = 0;
|
|
|
|
while ( paddrHostent = pHostent->h_addr_list[i++] )
|
|
{
|
|
freturn = RtlEqualMemory(
|
|
paddrHostent,
|
|
pAddr,
|
|
AddrLength );
|
|
if ( freturn )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return freturn;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
Hostent_IsIp4AddressInHostent(
|
|
IN OUT PHOSTENT pHostent,
|
|
IN IP4_ADDRESS Ip4Addr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does hostent contain this address.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- hostent to check
|
|
|
|
pAddr -- ptr to address to check
|
|
|
|
AddrLength -- address length
|
|
|
|
Family -- address family
|
|
|
|
Return Value:
|
|
|
|
TRUE if address is in hostent.
|
|
FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
DWORD i;
|
|
PCHAR paddrHostent;
|
|
|
|
//
|
|
// validate
|
|
// - must have hostent
|
|
// - length must match
|
|
//
|
|
|
|
if ( !pHostent ||
|
|
sizeof(IP4_ADDRESS) != (DWORD)pHostent->h_length )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// search for address -- if found return TRUE
|
|
//
|
|
|
|
i = 0;
|
|
|
|
while ( paddrHostent = pHostent->h_addr_list[i++] )
|
|
{
|
|
if ( Ip4Addr == *(PIP4_ADDRESS)paddrHostent )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Hostent building utilities
|
|
//
|
|
|
|
DNS_STATUS
|
|
HostentBlob_Create(
|
|
IN OUT PHOSTENT_BLOB * ppBlob,
|
|
IN PHOSTENT_INIT pReq
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize hostent (extending buffers as necessary)
|
|
|
|
May allocate hostent buffer if existing too small.
|
|
Returns required size.
|
|
|
|
Arguments:
|
|
|
|
ppBlob -- addr containing or to recv hostent object
|
|
|
|
pReq -- hostent init request
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PHOSTENT_BLOB pblob = *ppBlob;
|
|
PHOSTENT phost;
|
|
PCHAR pbuf;
|
|
BOOL funicode = FALSE;
|
|
DWORD bytesLeft;
|
|
DWORD addrSize;
|
|
DWORD addrType;
|
|
DWORD countAlias;
|
|
DWORD countAddr;
|
|
|
|
DWORD sizeChar;
|
|
DWORD sizeHostent = 0;
|
|
DWORD sizeAliasPtr;
|
|
DWORD sizeAddrPtr;
|
|
DWORD sizeAddrs;
|
|
DWORD sizeName;
|
|
DWORD sizeAliasNames;
|
|
DWORD sizeTotal;
|
|
|
|
DNSDBG( HOSTENT, ( "HostentBlob_Create()\n" ));
|
|
|
|
|
|
//
|
|
// calculate required size
|
|
//
|
|
|
|
// size for all char allocs
|
|
//
|
|
// note, we save CharSet info, if known, but the real
|
|
// action in sizing or building or printing strings is simply
|
|
// unicode\not-unicode
|
|
|
|
sizeChar = sizeof(CHAR);
|
|
if ( pReq->fUnicode || pReq->CharSet == DnsCharSetUnicode )
|
|
{
|
|
sizeChar = sizeof(WCHAR);
|
|
funicode = TRUE;
|
|
}
|
|
|
|
// limit alias count
|
|
|
|
countAlias = pReq->AliasCount;
|
|
if ( countAlias > DNS_MAX_ALIAS_COUNT )
|
|
{
|
|
countAlias = DNS_MAX_ALIAS_COUNT;
|
|
}
|
|
sizeAliasPtr = (countAlias+1) * sizeof(PCHAR);
|
|
|
|
// size address pointer array
|
|
// - always size for at least one address
|
|
// - write PTR address after record write
|
|
// - write loopback or other local address
|
|
// into local hostent
|
|
|
|
countAddr = pReq->AddrCount;
|
|
if ( countAddr == 0 )
|
|
{
|
|
countAddr = 1;
|
|
}
|
|
sizeAddrPtr = (countAddr+1) * sizeof(PCHAR);
|
|
|
|
//
|
|
// determine address size and type
|
|
// - may be specified directly
|
|
// - or picked up from DNS type
|
|
//
|
|
// DCR: functionalize type-to\from-family and addr size
|
|
//
|
|
|
|
addrType = pReq->AddrFamily;
|
|
|
|
if ( !addrType )
|
|
{
|
|
WORD wtype = pReq->wType;
|
|
|
|
if ( wtype == DNS_TYPE_A )
|
|
{
|
|
addrType = AF_INET;
|
|
}
|
|
else if ( wtype == DNS_TYPE_AAAA ||
|
|
wtype == DNS_TYPE_A6 )
|
|
{
|
|
addrType = AF_INET6;
|
|
}
|
|
else if ( wtype == DNS_TYPE_ATMA )
|
|
{
|
|
addrType = AF_ATM;
|
|
}
|
|
}
|
|
|
|
if ( addrType == AF_INET )
|
|
{
|
|
addrSize = sizeof(IP4_ADDRESS);
|
|
}
|
|
else if ( addrType == AF_INET6 )
|
|
{
|
|
addrSize = sizeof(IP6_ADDRESS );
|
|
}
|
|
else if ( addrType == AF_ATM )
|
|
{
|
|
addrSize = sizeof(ATM_ADDRESS);
|
|
}
|
|
else
|
|
{
|
|
// should have type and count or neither
|
|
DNS_ASSERT( pReq->AddrCount == 0 );
|
|
addrSize = 0;
|
|
}
|
|
|
|
sizeAddrs = countAddr * addrSize;
|
|
|
|
// always have buffer large enough for one
|
|
// address of largest type
|
|
|
|
if ( sizeAddrs < MIN_ADDR_BUF_SIZE )
|
|
{
|
|
sizeAddrs = MIN_ADDR_BUF_SIZE;
|
|
}
|
|
|
|
//
|
|
// namelength
|
|
// - if actual name use it
|
|
// (charset must match type we're building)
|
|
// - if size, use it
|
|
// - if absent use MAX
|
|
// - round to DWORD
|
|
|
|
if ( pReq->pName )
|
|
{
|
|
if ( funicode )
|
|
{
|
|
sizeName = wcslen( (PWSTR)pReq->pName );
|
|
}
|
|
else
|
|
{
|
|
sizeName = strlen( pReq->pName );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sizeName = pReq->NameLength;
|
|
}
|
|
|
|
if ( sizeName )
|
|
{
|
|
sizeName++;
|
|
}
|
|
else
|
|
{
|
|
sizeName = DNS_MAX_NAME_BUFFER_LENGTH;
|
|
}
|
|
sizeName = HOSTENT_STRING_ALIGN_DWORD( sizeChar*sizeName );
|
|
|
|
//
|
|
// alias name lengths
|
|
// - if absent use MAX for each string
|
|
// - round to DWORD
|
|
//
|
|
|
|
sizeAliasNames = pReq->AliasNameLength;
|
|
|
|
if ( sizeAliasNames )
|
|
{
|
|
sizeAliasNames += pReq->AliasCount;
|
|
}
|
|
else
|
|
{
|
|
sizeAliasNames = DNS_MAX_NAME_BUFFER_LENGTH;
|
|
}
|
|
sizeAliasNames = HOSTENT_STRING_ALIGN_DWORD( sizeChar*sizeAliasNames );
|
|
|
|
|
|
//
|
|
// calc total size
|
|
//
|
|
// note: be careful of alignment issues
|
|
// our layout is
|
|
// - hostent struct
|
|
// - ptr arrays
|
|
// - address + string data
|
|
//
|
|
// since address and string DATA (not ptrs) can be intermixed
|
|
// as we build, we MUST size strings for DWORD (at minimum) so
|
|
// to that addresses may be DWORD aligned
|
|
//
|
|
|
|
sizeTotal = POINTER_ALIGN_DWORD( sizeof(HOSTENT) ) +
|
|
sizeAliasPtr +
|
|
sizeAddrPtr +
|
|
sizeAddrs +
|
|
sizeName +
|
|
sizeAliasNames;
|
|
|
|
//
|
|
// if no blob, allocate one along with buffer
|
|
//
|
|
|
|
if ( !pblob )
|
|
{
|
|
pblob = (PHOSTENT_BLOB) ALLOCATE_HEAP( sizeTotal + sizeof(HOSTENT_BLOB) );
|
|
if ( !pblob )
|
|
{
|
|
goto Failed;
|
|
}
|
|
RtlZeroMemory( pblob, sizeof(*pblob) );
|
|
|
|
pbuf = (PCHAR) (pblob + 1);
|
|
pblob->pBuffer = pbuf;
|
|
pblob->BufferLength = sizeTotal;
|
|
pblob->fAllocatedBlob = TRUE;
|
|
pblob->fAllocatedBuf = FALSE;
|
|
}
|
|
|
|
//
|
|
// check existing buffer for size
|
|
// - allocate new buffer if necessary
|
|
//
|
|
|
|
else
|
|
{
|
|
pbuf = pblob->pBuffer;
|
|
|
|
if ( !pbuf || pblob->BufferLength < sizeTotal )
|
|
{
|
|
if ( pbuf && pblob->fAllocatedBuf )
|
|
{
|
|
FREE_HEAP( pbuf );
|
|
}
|
|
|
|
pbuf = ALLOCATE_HEAP( sizeTotal );
|
|
pblob->pBuffer = pbuf;
|
|
|
|
if ( pbuf )
|
|
{
|
|
pblob->BufferLength = sizeTotal;
|
|
pblob->fAllocatedBuf = TRUE;
|
|
}
|
|
|
|
//
|
|
// DCR: alloc failure handling
|
|
// - possibly keep previous buffers limitations
|
|
//
|
|
|
|
else // alloc failed
|
|
{
|
|
pblob->fAllocatedBuf = FALSE;
|
|
return( DNS_ERROR_NO_MEMORY );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// init hostent and buffer subfields
|
|
//
|
|
|
|
bytesLeft = pblob->BufferLength;
|
|
|
|
//
|
|
// hostent
|
|
//
|
|
|
|
phost = (PHOSTENT) pbuf;
|
|
pbuf += sizeof(HOSTENT);
|
|
bytesLeft -= sizeof(HOSTENT);
|
|
|
|
pblob->pHostent = phost;
|
|
|
|
phost->h_name = NULL;
|
|
phost->h_addr_list = NULL;
|
|
phost->h_aliases = NULL;
|
|
phost->h_length = (SHORT) addrSize;
|
|
phost->h_addrtype = (SHORT) addrType;
|
|
|
|
pblob->fWroteName = FALSE;
|
|
pblob->AliasCount = 0;
|
|
pblob->AddrCount = 0;
|
|
pblob->CharSet = pReq->CharSet;
|
|
pblob->fUnicode = funicode;
|
|
if ( funicode )
|
|
{
|
|
pblob->CharSet = DnsCharSetUnicode;
|
|
}
|
|
|
|
//
|
|
// init alias array
|
|
// - set hostent ptr
|
|
// - clear entire alias array;
|
|
// since this count is often defaulted nice to clear it just
|
|
// to avoid junk
|
|
//
|
|
//
|
|
|
|
#if 0
|
|
pwrite = FlatBuf_ReserveAlignPointer(
|
|
& pbuf,
|
|
& bytesLeft,
|
|
sizeAliasPtr );
|
|
#endif
|
|
|
|
if ( bytesLeft < sizeAliasPtr )
|
|
{
|
|
DNS_ASSERT( FALSE );
|
|
goto Failed;
|
|
}
|
|
RtlZeroMemory(
|
|
pbuf,
|
|
sizeAliasPtr );
|
|
|
|
phost->h_aliases = (PCHAR *) pbuf;
|
|
|
|
pbuf += sizeAliasPtr;
|
|
bytesLeft -= sizeAliasPtr;
|
|
|
|
pblob->MaxAliasCount = countAlias;
|
|
|
|
//
|
|
// init addr array
|
|
// - set hostent ptr
|
|
// - clear first address entry
|
|
// callers responsibility to NULL last addr pointer when done
|
|
//
|
|
|
|
if ( bytesLeft < sizeAddrPtr )
|
|
{
|
|
DNS_ASSERT( FALSE );
|
|
goto Failed;
|
|
}
|
|
* (PCHAR *)pbuf = NULL;
|
|
phost->h_addr_list = (PCHAR *) pbuf;
|
|
|
|
pbuf += sizeAddrPtr;
|
|
bytesLeft -= sizeAddrPtr;
|
|
|
|
pblob->MaxAddrCount = countAddr;
|
|
|
|
//
|
|
// set remaining buffer info
|
|
// - save current buffer space
|
|
// - save data on part of buffer available
|
|
// for use by data
|
|
//
|
|
|
|
pblob->pAvailBuffer = pbuf;
|
|
pblob->AvailLength = bytesLeft;
|
|
|
|
pblob->pCurrent = pbuf;
|
|
pblob->BytesLeft = bytesLeft;
|
|
|
|
*ppBlob = pblob;
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_HostentBlob(
|
|
"HostentBlob After Create:",
|
|
pblob );
|
|
}
|
|
|
|
return( ERROR_SUCCESS );
|
|
|
|
|
|
Failed:
|
|
|
|
*ppBlob = pblob;
|
|
|
|
if ( pblob && pblob->pBuffer && pblob->fAllocatedBuf )
|
|
{
|
|
FREE_HEAP( pblob->pBuffer );
|
|
pblob->pBuffer = NULL;
|
|
pblob->fAllocatedBuf = FALSE;
|
|
}
|
|
|
|
DNSDBG( HOSTENT, ( "Hostent Blob create failed!\n" ));
|
|
|
|
return( DNS_ERROR_NO_MEMORY );
|
|
}
|
|
|
|
|
|
|
|
PHOSTENT_BLOB
|
|
HostentBlob_CreateAttachExisting(
|
|
IN PHOSTENT pHostent,
|
|
IN BOOL fUnicode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create hostent blob for existing hostent.
|
|
|
|
This is a hack to allow existing RnR TLS hostents to
|
|
be attached to hostent-blobs to smooth code transition.
|
|
|
|
A full version would obviously require init structure and
|
|
separate the sizing\init function from the creation
|
|
function.
|
|
|
|
Arguments:
|
|
|
|
pHostent -- existing hostent
|
|
|
|
fUnicode -- is unicode
|
|
|
|
Return Value:
|
|
|
|
Ptr to new hostent blob.
|
|
NULL on alloc failure. GetLastError() has error.
|
|
|
|
--*/
|
|
{
|
|
PHOSTENT_BLOB pblob;
|
|
|
|
DNSDBG( HOSTENT, ( "HostentBlob_CreateAttachExisting()\n" ));
|
|
|
|
//
|
|
// alloc
|
|
//
|
|
|
|
pblob = (PHOSTENT_BLOB) ALLOCATE_HEAP_ZERO( sizeof(HOSTENT_BLOB) );
|
|
if ( !pblob )
|
|
{
|
|
SetLastError( DNS_ERROR_NO_MEMORY );
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// attach existing hostent
|
|
//
|
|
|
|
pblob->pHostent = pHostent;
|
|
pblob->fUnicode = fUnicode;
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_HostentBlob(
|
|
"Leaving AttachExisting:",
|
|
pblob );
|
|
}
|
|
|
|
return pblob;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
HostentBlob_Free(
|
|
IN OUT PHOSTENT_BLOB pBlob
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free hostent blob.
|
|
|
|
Arguments:
|
|
|
|
pBlob -- blob to free
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// free buffer?
|
|
//
|
|
|
|
if ( !pBlob )
|
|
{
|
|
return;
|
|
}
|
|
if ( pBlob->fAllocatedBuf )
|
|
{
|
|
FREE_HEAP( pBlob->pBuffer );
|
|
pBlob->pBuffer = NULL;
|
|
pBlob->fAllocatedBuf = FALSE;
|
|
}
|
|
|
|
//
|
|
// free blob itself?
|
|
//
|
|
|
|
if ( pBlob->fAllocatedBlob )
|
|
{
|
|
FREE_HEAP( pBlob );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
HostentBlob_WriteAddress(
|
|
IN OUT PHOSTENT_BLOB pBlob,
|
|
IN PVOID pAddress,
|
|
IN DWORD AddrSize,
|
|
IN DWORD AddrType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write IP4 address to hostent blob.
|
|
|
|
Arguments:
|
|
|
|
pBlob -- hostent build blob
|
|
|
|
pAddress - address to write
|
|
|
|
AddrSize - address size
|
|
|
|
AddrType - address type (hostent type, e.g. AF_INET)
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ERROR_MORE_DATA if out of buffer space
|
|
ERROR_INVALID_DATA if address doesn't match hostent
|
|
|
|
--*/
|
|
{
|
|
DWORD count = pBlob->AddrCount;
|
|
PHOSTENT phost = pBlob->pHostent;
|
|
PCHAR pcurrent;
|
|
DWORD bytesLeft;
|
|
|
|
// verify type
|
|
// - set if empty or no addresses written
|
|
|
|
if ( phost->h_addrtype != (SHORT)AddrType )
|
|
{
|
|
if ( phost->h_addrtype != 0 )
|
|
{
|
|
return( ERROR_INVALID_DATA );
|
|
}
|
|
phost->h_addrtype = (SHORT) AddrType;
|
|
phost->h_length = (SHORT) AddrSize;
|
|
}
|
|
|
|
// verify space
|
|
|
|
if ( count >= pBlob->MaxAddrCount )
|
|
{
|
|
return( ERROR_MORE_DATA );
|
|
}
|
|
|
|
// align - to DWORD
|
|
|
|
pcurrent = DWORD_ALIGN( pBlob->pCurrent );
|
|
bytesLeft = pBlob->BytesLeft;
|
|
bytesLeft -= (DWORD)(pcurrent - pBlob->pCurrent);
|
|
|
|
if ( bytesLeft < AddrSize )
|
|
{
|
|
return( ERROR_MORE_DATA );
|
|
}
|
|
|
|
// copy
|
|
// - copy address to buffer
|
|
// - set pointer in addr list
|
|
// NULL following pointer
|
|
|
|
RtlCopyMemory(
|
|
pcurrent,
|
|
pAddress,
|
|
AddrSize );
|
|
|
|
phost->h_addr_list[count++] = pcurrent;
|
|
phost->h_addr_list[count] = NULL;
|
|
pBlob->AddrCount = count;
|
|
|
|
pBlob->pCurrent = pcurrent + AddrSize;
|
|
pBlob->BytesLeft = bytesLeft - AddrSize;
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
HostentBlob_WriteAddressArray(
|
|
IN OUT PHOSTENT_BLOB pBlob,
|
|
IN PVOID pAddrArray,
|
|
IN DWORD AddrCount,
|
|
IN DWORD AddrSize,
|
|
IN DWORD AddrType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write address array to hostent blob.
|
|
|
|
Arguments:
|
|
|
|
pBlob -- hostent build blob
|
|
|
|
pAddrArray - address array to write
|
|
|
|
AddrCount - address count
|
|
|
|
AddrSize - address size
|
|
|
|
AddrType - address type (hostent type, e.g. AF_INET)
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ERROR_MORE_DATA if out of buffer space
|
|
ERROR_INVALID_DATA if address doesn't match hostent
|
|
|
|
--*/
|
|
{
|
|
DWORD count = AddrCount;
|
|
PHOSTENT phost = pBlob->pHostent;
|
|
PCHAR pcurrent;
|
|
DWORD totalSize;
|
|
DWORD i;
|
|
DWORD bytesLeft;
|
|
|
|
// verify type
|
|
// - set if empty or no addresses written
|
|
|
|
if ( phost->h_addrtype != (SHORT)AddrType )
|
|
{
|
|
if ( phost->h_addrtype != 0 )
|
|
{
|
|
return( ERROR_INVALID_DATA );
|
|
}
|
|
phost->h_addrtype = (SHORT) AddrType;
|
|
phost->h_length = (SHORT) AddrSize;
|
|
}
|
|
|
|
// verify space
|
|
|
|
if ( count > pBlob->MaxAddrCount )
|
|
{
|
|
return( ERROR_MORE_DATA );
|
|
}
|
|
|
|
// align - to DWORD
|
|
//
|
|
// note: we are assuming that pAddrArray is internally
|
|
// aligned adequately, otherwise we wouldn't be
|
|
// getting an intact array and would have to add serially
|
|
|
|
pcurrent = DWORD_ALIGN( pBlob->pCurrent );
|
|
bytesLeft = pBlob->BytesLeft;
|
|
bytesLeft -= (DWORD)(pcurrent - pBlob->pCurrent);
|
|
|
|
totalSize = count * AddrSize;
|
|
|
|
if ( bytesLeft < totalSize )
|
|
{
|
|
return( ERROR_MORE_DATA );
|
|
}
|
|
|
|
// copy
|
|
// - copy address array to buffer
|
|
// - set pointer to each address in array
|
|
// - NULL following pointer
|
|
|
|
RtlCopyMemory(
|
|
pcurrent,
|
|
pAddrArray,
|
|
totalSize );
|
|
|
|
for ( i=0; i<count; i++ )
|
|
{
|
|
phost->h_addr_list[i] = pcurrent;
|
|
pcurrent += AddrSize;
|
|
}
|
|
phost->h_addr_list[count] = NULL;
|
|
pBlob->AddrCount = count;
|
|
|
|
pBlob->pCurrent = pcurrent;
|
|
pBlob->BytesLeft = bytesLeft - totalSize;
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
HostentBlob_WriteNameOrAlias(
|
|
IN OUT PHOSTENT_BLOB pBlob,
|
|
IN PSTR pszName,
|
|
IN BOOL fAlias,
|
|
IN BOOL fUnicode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write name or alias to hostent
|
|
|
|
Arguments:
|
|
|
|
pBlob -- hostent build blob
|
|
|
|
pszName -- name to write
|
|
|
|
fAlias -- TRUE for alias; FALSE for name
|
|
|
|
fUnicode -- name is unicode
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ERROR_MORE_DATA if out of buffer space
|
|
ERROR_INVALID_DATA if address doesn't match hostent
|
|
|
|
--*/
|
|
{
|
|
DWORD count = pBlob->AliasCount;
|
|
PHOSTENT phost = pBlob->pHostent;
|
|
DWORD length;
|
|
PCHAR pcurrent;
|
|
DWORD bytesLeft;
|
|
|
|
//
|
|
// check length
|
|
//
|
|
|
|
if ( fUnicode )
|
|
{
|
|
length = (wcslen( (PCWSTR)pszName ) + 1) * sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
length = strlen( pszName ) + 1;
|
|
}
|
|
|
|
//
|
|
// verify space
|
|
// included ptr space
|
|
// - skip if already written name
|
|
// or exhausted alias array
|
|
//
|
|
|
|
if ( fAlias )
|
|
{
|
|
if ( count >= pBlob->MaxAliasCount )
|
|
{
|
|
return( ERROR_MORE_DATA );
|
|
}
|
|
}
|
|
else if ( pBlob->fWroteName )
|
|
{
|
|
return( ERROR_MORE_DATA );
|
|
}
|
|
|
|
// align
|
|
|
|
pcurrent = REQUIRED_HOSTENT_STRING_ALIGN_PTR( pBlob->pCurrent );
|
|
bytesLeft = pBlob->BytesLeft;
|
|
bytesLeft -= (DWORD)(pcurrent - pBlob->pCurrent);
|
|
|
|
if ( bytesLeft < length )
|
|
{
|
|
return( ERROR_MORE_DATA );
|
|
}
|
|
|
|
// copy
|
|
// - copy address to buffer
|
|
// - set pointer in addr list
|
|
// NULL following pointer
|
|
|
|
RtlCopyMemory(
|
|
pcurrent,
|
|
pszName,
|
|
length );
|
|
|
|
if ( fAlias )
|
|
{
|
|
phost->h_aliases[count++] = pcurrent;
|
|
phost->h_aliases[count] = NULL;
|
|
pBlob->AliasCount = count;
|
|
}
|
|
else
|
|
{
|
|
phost->h_name = pcurrent;
|
|
pBlob->fWroteName = TRUE;
|
|
}
|
|
|
|
length = REQUIRED_HOSTENT_STRING_ALIGN_DWORD( length );
|
|
pBlob->pCurrent = pcurrent + length;
|
|
pBlob->BytesLeft = bytesLeft - length;
|
|
|
|
return( NO_ERROR );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
HostentBlob_WriteRecords(
|
|
IN OUT PHOSTENT_BLOB pBlob,
|
|
IN PDNS_RECORD pRecords,
|
|
IN BOOL fWriteName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write name or alias to hostent
|
|
|
|
Arguments:
|
|
|
|
pBlob -- hostent build blob
|
|
|
|
pRecords -- records to convert to hostent
|
|
|
|
fWriteName -- write name
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS if successful.
|
|
ERROR_MORE_DATA if out of buffer space
|
|
ERROR_INVALID_DATA if address doesn't match hostent
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD prr = pRecords;
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"HostentBlob_WriteRecords( %p, %p, %d )\n",
|
|
pBlob,
|
|
pRecords,
|
|
fWriteName ));
|
|
|
|
//
|
|
// write each record in turn to hostent
|
|
//
|
|
|
|
while ( prr )
|
|
{
|
|
WORD wtype;
|
|
|
|
if ( prr->Flags.S.Section != DNSREC_ANSWER &&
|
|
prr->Flags.S.Section != 0 )
|
|
{
|
|
prr = prr->pNext;
|
|
continue;
|
|
}
|
|
|
|
wtype = prr->wType;
|
|
|
|
switch( wtype )
|
|
{
|
|
case DNS_TYPE_A:
|
|
|
|
status = HostentBlob_WriteAddress(
|
|
pBlob,
|
|
&prr->Data.A.IpAddress,
|
|
sizeof(IP4_ADDRESS),
|
|
AF_INET );
|
|
break;
|
|
|
|
case DNS_TYPE_AAAA:
|
|
|
|
status = HostentBlob_WriteAddress(
|
|
pBlob,
|
|
&prr->Data.AAAA.Ip6Address,
|
|
sizeof(IP6_ADDRESS),
|
|
AF_INET6 );
|
|
break;
|
|
|
|
case DNS_TYPE_ATMA:
|
|
{
|
|
ATM_ADDRESS atmAddr;
|
|
|
|
// DCR: functionalize ATMA to ATM conversion
|
|
// not sure this num of digits is correct
|
|
// may have to actually parse address
|
|
|
|
atmAddr.AddressType = prr->Data.ATMA.AddressType;
|
|
atmAddr.NumofDigits = ATM_ADDR_SIZE;
|
|
RtlCopyMemory(
|
|
& atmAddr.Addr,
|
|
prr->Data.ATMA.Address,
|
|
ATM_ADDR_SIZE );
|
|
|
|
status = HostentBlob_WriteAddress(
|
|
pBlob,
|
|
& atmAddr,
|
|
sizeof(ATM_ADDRESS),
|
|
AF_ATM );
|
|
break;
|
|
}
|
|
|
|
case DNS_TYPE_CNAME:
|
|
|
|
// record name is an alias
|
|
|
|
status = HostentBlob_WriteNameOrAlias(
|
|
pBlob,
|
|
prr->pName,
|
|
TRUE, // alias
|
|
(prr->Flags.S.CharSet == DnsCharSetUnicode)
|
|
);
|
|
break;
|
|
|
|
case DNS_TYPE_PTR:
|
|
|
|
// target name is the hostent name
|
|
// but if already wrote name, PTR target becomes alias
|
|
|
|
status = HostentBlob_WriteNameOrAlias(
|
|
pBlob,
|
|
prr->Data.PTR.pNameHost,
|
|
pBlob->fWroteName
|
|
? TRUE // alias
|
|
: FALSE, // name
|
|
(prr->Flags.S.CharSet == DnsCharSetUnicode)
|
|
);
|
|
break;
|
|
|
|
default:
|
|
|
|
DNSDBG( ANY, (
|
|
"Error record of type = %d while building hostent!\n",
|
|
wtype ));
|
|
status = ERROR_INVALID_DATA;
|
|
}
|
|
|
|
if ( status != ERROR_SUCCESS )
|
|
{
|
|
DNSDBG( ANY, (
|
|
"ERROR: failed writing record to hostent!\n"
|
|
"\tprr = %p\n"
|
|
"\ttype = %d\n"
|
|
"\tstatus = %d\n",
|
|
prr,
|
|
wtype,
|
|
status ));
|
|
}
|
|
|
|
prr = prr->pNext;
|
|
}
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_HostentBlob(
|
|
"HostentBlob after WriteRecords():",
|
|
pBlob );
|
|
}
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
HostentBlob_CreateFromRecords(
|
|
IN OUT PHOSTENT_BLOB * ppBlob,
|
|
IN PDNS_RECORD pRecords,
|
|
IN BOOL fWriteName,
|
|
IN INT AddrFamily, OPTIONAL
|
|
IN WORD wType OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create hostent from records
|
|
|
|
Arguments:
|
|
|
|
ppBlob -- ptr with or to recv hostent blob
|
|
|
|
pRecords -- records to convert to hostent
|
|
|
|
fWriteName -- write name to hostent
|
|
|
|
AddrFamily -- addr family use if PTR records and no addr
|
|
|
|
wType -- query type, if known
|
|
|
|
Return Value:
|
|
|
|
Ptr to blob if successful.
|
|
NULL on error; GetLastError() has error.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD prrFirstAddr = NULL;
|
|
PDNS_RECORD prr;
|
|
DWORD addrCount = 0;
|
|
WORD addrType = 0;
|
|
HOSTENT_INIT request;
|
|
PHOSTENT_BLOB pblob = *ppBlob;
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"HostentBlob_CreateFromRecords()\n"
|
|
"\tpblob = %p\n"
|
|
"\tprr = %p\n",
|
|
pblob,
|
|
pRecords ));
|
|
|
|
//
|
|
// count addresses
|
|
//
|
|
// DCR: fix up section hack when hosts file records get ANSWER section
|
|
//
|
|
|
|
prr = pRecords;
|
|
|
|
while ( prr )
|
|
{
|
|
if ( ( prr->Flags.S.Section == 0 ||
|
|
prr->Flags.S.Section == DNSREC_ANSWER )
|
|
&&
|
|
Hostent_IsSupportedAddrType( prr->wType ) )
|
|
{
|
|
addrCount++;
|
|
if ( !prrFirstAddr )
|
|
{
|
|
prrFirstAddr = prr;
|
|
addrType = prr->wType;
|
|
}
|
|
}
|
|
prr = prr->pNext;
|
|
}
|
|
|
|
//
|
|
// create or reinit hostent blob
|
|
//
|
|
|
|
RtlZeroMemory( &request, sizeof(request) );
|
|
|
|
request.AliasCount = DNS_MAX_ALIAS_COUNT;
|
|
request.AddrCount = addrCount;
|
|
request.wType = addrType;
|
|
if ( !addrType )
|
|
{
|
|
request.AddrFamily = AddrFamily;
|
|
}
|
|
request.CharSet = (pRecords)
|
|
? pRecords->Flags.S.CharSet
|
|
: DnsCharSetUnicode;
|
|
|
|
status = HostentBlob_Create(
|
|
& pblob,
|
|
& request );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// build hostent from answer records
|
|
//
|
|
// note: if manage to extract any useful data => continue
|
|
// this protects against new unwriteable records breaking us
|
|
//
|
|
|
|
status = HostentBlob_WriteRecords(
|
|
pblob,
|
|
pRecords,
|
|
TRUE // write name
|
|
);
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
if ( pblob->AddrCount ||
|
|
pblob->AliasCount ||
|
|
pblob->fWroteName )
|
|
{
|
|
status = NO_ERROR;
|
|
}
|
|
else
|
|
{
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
//
|
|
// write address from PTR record
|
|
// - first record PTR
|
|
// OR
|
|
// - queried for PTR and got CNAME answer, which can happen
|
|
// in classless reverse lookup case
|
|
//
|
|
// DCR: add PTR address lookup to HostentBlob_WriteRecords()
|
|
// - natural place
|
|
// - but would have to figure out handling of multiple PTRs
|
|
//
|
|
|
|
if ( pRecords &&
|
|
( pRecords->wType == DNS_TYPE_PTR ||
|
|
( wType == DNS_TYPE_PTR &&
|
|
pRecords->wType == DNS_TYPE_CNAME &&
|
|
pRecords->Flags.S.Section == DNSREC_ANSWER ) ) )
|
|
{
|
|
IP6_ADDRESS ip6;
|
|
DWORD addrLength = sizeof(IP6_ADDRESS);
|
|
INT family = 0;
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Writing address for PTR record %S\n",
|
|
pRecords->pName ));
|
|
|
|
// convert reverse name to IP
|
|
|
|
if ( Dns_StringToAddressEx(
|
|
(PCHAR) & ip6,
|
|
& addrLength,
|
|
(PCSTR) pRecords->pName,
|
|
& family,
|
|
IS_UNICODE_RECORD(pRecords),
|
|
TRUE // reverse lookup name
|
|
) )
|
|
{
|
|
status = HostentBlob_WriteAddress(
|
|
pblob,
|
|
(PCHAR) &ip6,
|
|
addrLength,
|
|
family );
|
|
|
|
ASSERT( status == NO_ERROR );
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// write name?
|
|
// - write name from first address record
|
|
//
|
|
|
|
if ( !pblob->fWroteName &&
|
|
fWriteName &&
|
|
prrFirstAddr )
|
|
{
|
|
status = HostentBlob_WriteNameOrAlias(
|
|
pblob,
|
|
prrFirstAddr->pName,
|
|
FALSE, // name
|
|
(prrFirstAddr->Flags.S.CharSet == DnsCharSetUnicode)
|
|
);
|
|
}
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_HostentBlob(
|
|
"HostentBlob after CreateFromRecords():",
|
|
pblob );
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( status != NO_ERROR && pblob )
|
|
{
|
|
HostentBlob_Free( pblob );
|
|
pblob = NULL;
|
|
}
|
|
|
|
*ppBlob = pblob;
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Leave HostentBlob_CreateFromRecords() => status = %d\n",
|
|
status ));
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Hostent Query
|
|
//
|
|
|
|
PHOSTENT_BLOB
|
|
HostentBlob_Query(
|
|
IN PWSTR pwsName,
|
|
IN WORD wType,
|
|
IN DWORD Flags,
|
|
IN OUT PVOID * ppMsg, OPTIONAL
|
|
IN INT AddrFamily OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Query DNS to create hostent.
|
|
|
|
Arguments:
|
|
|
|
pwsName -- name to query
|
|
|
|
wType -- query type
|
|
|
|
Flags -- query flags
|
|
|
|
ppMsg -- addr to recv ptr to message
|
|
|
|
AddrType -- address type (family) to reserve space for if querying
|
|
for PTR records
|
|
|
|
Return Value:
|
|
|
|
Ptr to blob if successful.
|
|
NULL on error; GetLastError() has error.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD prrQuery = NULL;
|
|
PHOSTENT_BLOB pblob = NULL;
|
|
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"HostentBlob_Query()\n"
|
|
"\tname = %S\n"
|
|
"\ttype = %d\n"
|
|
"\tflags = %08x\n"
|
|
"\tmsg out = %p\n",
|
|
pwsName,
|
|
wType,
|
|
Flags,
|
|
ppMsg ));
|
|
|
|
|
|
//
|
|
// query
|
|
// - if fails, dump any message before return
|
|
//
|
|
|
|
status = DnsQuery_W(
|
|
pwsName,
|
|
wType,
|
|
Flags,
|
|
NULL,
|
|
&prrQuery,
|
|
ppMsg );
|
|
|
|
// if failed, dump any message
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
if ( ppMsg && *ppMsg )
|
|
{
|
|
DnsApiFree( *ppMsg );
|
|
*ppMsg = NULL;
|
|
}
|
|
if ( status == RPC_S_SERVER_UNAVAILABLE )
|
|
{
|
|
status = WSATRY_AGAIN;
|
|
}
|
|
goto Done;
|
|
}
|
|
|
|
if ( !prrQuery )
|
|
{
|
|
ASSERT( FALSE );
|
|
status = DNS_ERROR_RCODE_NAME_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// build hostent
|
|
//
|
|
|
|
status = HostentBlob_CreateFromRecords(
|
|
& pblob,
|
|
prrQuery,
|
|
TRUE, // write name from first answer
|
|
AddrFamily,
|
|
wType
|
|
);
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// failed name write
|
|
// - PTR queries that CNAME but don't find a PTR can hit here
|
|
//
|
|
|
|
if ( !pblob->fWroteName )
|
|
{
|
|
DNS_ASSERT( wType == DNS_TYPE_PTR );
|
|
status = DNS_INFO_NO_RECORDS;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// for address query must get answer
|
|
//
|
|
// DCR: DnsQuery() should convert to no-records on empty CNAME chain?
|
|
// DCR: should we go ahead and build hostent?
|
|
//
|
|
|
|
if ( pblob->AddrCount == 0 && Hostent_IsSupportedAddrType(wType) )
|
|
{
|
|
status = DNS_INFO_NO_RECORDS;
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( prrQuery )
|
|
{
|
|
DnsRecordListFree(
|
|
prrQuery,
|
|
DnsFreeRecordListDeep );
|
|
}
|
|
|
|
if ( status != NO_ERROR && pblob )
|
|
{
|
|
HostentBlob_Free( pblob );
|
|
pblob = NULL;
|
|
}
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Leave HostentBlob_Query()\n"
|
|
"\tpblob = %p\n"
|
|
"\tstatus = %d\n",
|
|
pblob,
|
|
status ));
|
|
|
|
SetLastError( status );
|
|
|
|
return( pblob );
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Special hostents
|
|
//
|
|
|
|
PHOSTENT_BLOB
|
|
HostentBlob_Localhost(
|
|
IN INT Family
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create hostent from records
|
|
|
|
Arguments:
|
|
|
|
AddrFamily -- address family
|
|
|
|
Return Value:
|
|
|
|
Ptr to blob if successful.
|
|
NULL on error; GetLastError() has error.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PDNS_RECORD prrFirstAddr = NULL;
|
|
PDNS_RECORD prr;
|
|
DWORD addrCount = 0;
|
|
DWORD addrSize;
|
|
CHAR addrBuf[ sizeof(IP6_ADDRESS ) ];
|
|
HOSTENT_INIT request;
|
|
PHOSTENT_BLOB pblob = NULL;
|
|
|
|
DNSDBG( HOSTENT, ( "HostentBlob_Localhost()\n" ));
|
|
|
|
//
|
|
// create hostent blob
|
|
//
|
|
|
|
RtlZeroMemory( &request, sizeof(request) );
|
|
|
|
request.AliasCount = 1;
|
|
request.AddrCount = 1;
|
|
request.AddrFamily = Family;
|
|
request.fUnicode = TRUE;
|
|
|
|
status = HostentBlob_Create(
|
|
& pblob,
|
|
& request );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// write in loopback address
|
|
//
|
|
|
|
if ( Family == AF_INET )
|
|
{
|
|
* (PIP4_ADDRESS) addrBuf = DNS_NET_ORDER_LOOPBACK;
|
|
addrSize = sizeof(IP4_ADDRESS);
|
|
}
|
|
else if ( Family == AF_INET6 )
|
|
{
|
|
IP6_SET_ADDR_LOOPBACK( (PIP6_ADDRESS)addrBuf );
|
|
addrSize = sizeof(IN6_ADDR);
|
|
}
|
|
else
|
|
{
|
|
status = DNS_ERROR_INVALID_DATA;
|
|
goto Done;
|
|
}
|
|
|
|
status = HostentBlob_WriteAddress(
|
|
pblob,
|
|
addrBuf,
|
|
addrSize,
|
|
Family );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// write localhost
|
|
//
|
|
|
|
status = HostentBlob_WriteNameOrAlias(
|
|
pblob,
|
|
(PSTR) L"localhost",
|
|
FALSE, // name
|
|
TRUE // unicode
|
|
);
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_HostentBlob(
|
|
"HostentBlob after localhost create:",
|
|
pblob );
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( status != NO_ERROR && pblob )
|
|
{
|
|
HostentBlob_Free( pblob );
|
|
pblob = NULL;
|
|
}
|
|
|
|
SetLastError( status );
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Leave Hostent_Localhost() => status = %d\n",
|
|
status ));
|
|
|
|
return( pblob );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
HostentBlob_CreateFromIpArray(
|
|
IN OUT PHOSTENT_BLOB * ppBlob,
|
|
IN INT AddrFamily,
|
|
IN INT AddrSize,
|
|
IN INT AddrCount,
|
|
IN PCHAR pArray,
|
|
IN PSTR pName,
|
|
IN BOOL fUnicode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create hostent from records
|
|
|
|
Arguments:
|
|
|
|
ppBlob -- ptr with or to recv hostent blob
|
|
|
|
AddrFamily -- addr family use if PTR records and no addr
|
|
|
|
pArray -- array of addresses
|
|
|
|
pName -- name for hostent
|
|
|
|
fUnicode --
|
|
TRUE if name is and hostent will be in unicode
|
|
FALSE for narrow name and hostent
|
|
|
|
Return Value:
|
|
|
|
Ptr to blob if successful.
|
|
NULL on error; GetLastError() has error.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
HOSTENT_INIT request;
|
|
PHOSTENT_BLOB pblob = *ppBlob;
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"HostentBlob_CreateFromIpArray()\n"
|
|
"\tppBlob = %p\n"
|
|
"\tfamily = %d\n"
|
|
"\tsize = %d\n"
|
|
"\tcount = %d\n"
|
|
"\tpArray = %p\n",
|
|
ppBlob,
|
|
AddrFamily,
|
|
AddrSize,
|
|
AddrCount,
|
|
pArray ));
|
|
|
|
|
|
//
|
|
// create or reinit hostent blob
|
|
//
|
|
|
|
RtlZeroMemory( &request, sizeof(request) );
|
|
|
|
request.AliasCount = DNS_MAX_ALIAS_COUNT;
|
|
request.AddrCount = AddrCount;
|
|
request.AddrFamily = AddrFamily;
|
|
request.fUnicode = fUnicode;
|
|
request.pName = pName;
|
|
|
|
status = HostentBlob_Create(
|
|
& pblob,
|
|
& request );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// write in array
|
|
//
|
|
|
|
if ( AddrCount )
|
|
{
|
|
status = HostentBlob_WriteAddressArray(
|
|
pblob,
|
|
pArray,
|
|
AddrCount,
|
|
AddrSize,
|
|
AddrFamily
|
|
);
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
//
|
|
// write name?
|
|
//
|
|
|
|
if ( pName )
|
|
{
|
|
status = HostentBlob_WriteNameOrAlias(
|
|
pblob,
|
|
pName,
|
|
FALSE, // name not alias
|
|
fUnicode
|
|
);
|
|
}
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_HostentBlob(
|
|
"Leaving HostentBlob_CreateFromIpArray():",
|
|
pblob );
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( status != NO_ERROR && pblob )
|
|
{
|
|
HostentBlob_Free( pblob );
|
|
pblob = NULL;
|
|
}
|
|
|
|
*ppBlob = pblob;
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Leave HostentBlob_CreateFromIpArray() => status = %d\n",
|
|
status ));
|
|
|
|
return( status );
|
|
}
|
|
|
|
|
|
|
|
DNS_STATUS
|
|
HostentBlob_CreateLocal(
|
|
IN OUT PHOSTENT_BLOB * ppBlob,
|
|
IN INT AddrFamily,
|
|
IN BOOL fLoopback,
|
|
IN BOOL fZero,
|
|
IN BOOL fHostnameOnly
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create hostent from records
|
|
|
|
Arguments:
|
|
|
|
ppBlob -- ptr with or to recv hostent blob
|
|
|
|
AddrFamily -- addr family use if PTR records and no addr
|
|
|
|
Return Value:
|
|
|
|
Ptr to blob if successful.
|
|
NULL on error; GetLastError() has error.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = NO_ERROR;
|
|
PHOSTENT_BLOB pblob = NULL;
|
|
WORD wtype;
|
|
INT size;
|
|
IP6_ADDRESS ip;
|
|
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"HostentBlob_CreateLocal()\n"
|
|
"\tppBlob = %p\n"
|
|
"\tfamily = %d\n"
|
|
"\tfLoopback = %d\n"
|
|
"\tfZero = %d\n"
|
|
"\tfHostname = %d\n",
|
|
ppBlob,
|
|
AddrFamily,
|
|
fLoopback,
|
|
fZero,
|
|
fHostnameOnly
|
|
));
|
|
|
|
//
|
|
// get family info
|
|
// - start with override IP = 0
|
|
// - if loopback switch to appropriate loopback
|
|
//
|
|
|
|
RtlZeroMemory(
|
|
&ip,
|
|
sizeof(ip) );
|
|
|
|
if ( AddrFamily == AF_INET )
|
|
{
|
|
wtype = DNS_TYPE_A;
|
|
size = sizeof(IP4_ADDRESS);
|
|
|
|
if ( fLoopback )
|
|
{
|
|
* (PIP4_ADDRESS) &ip = DNS_NET_ORDER_LOOPBACK;
|
|
}
|
|
}
|
|
else if ( AddrFamily == AF_INET6 )
|
|
{
|
|
wtype = DNS_TYPE_AAAA;
|
|
size = sizeof(IP6_ADDRESS);
|
|
|
|
if ( fLoopback )
|
|
{
|
|
IP6_SET_ADDR_LOOPBACK( &ip );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERROR_INVALID_PARAMETER;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// query for local host info
|
|
//
|
|
|
|
pblob = HostentBlob_Query(
|
|
NULL, // NULL name gets local host data
|
|
wtype,
|
|
0, // standard query
|
|
NULL, // no message
|
|
AddrFamily );
|
|
if ( !pblob )
|
|
{
|
|
DNS_ASSERT( FALSE );
|
|
status = GetLastError();
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// overwrite with specific address
|
|
//
|
|
|
|
if ( fLoopback || fZero )
|
|
{
|
|
if ( ! Hostent_SetToSingleAddress(
|
|
pblob->pHostent,
|
|
(PCHAR) &ip,
|
|
size ) )
|
|
{
|
|
DNS_ASSERT( pblob->AddrCount == 0 );
|
|
|
|
pblob->AddrCount = 0;
|
|
|
|
status = HostentBlob_WriteAddress(
|
|
pblob,
|
|
& ip,
|
|
size,
|
|
AddrFamily );
|
|
if ( status != NO_ERROR )
|
|
{
|
|
DNS_ASSERT( status!=NO_ERROR );
|
|
goto Done;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// for gethostname()
|
|
// - chop name down to just hostname
|
|
// - kill off aliases
|
|
//
|
|
|
|
if ( fHostnameOnly )
|
|
{
|
|
PWSTR pname = (PWSTR) pblob->pHostent->h_name;
|
|
PWSTR pdomain;
|
|
|
|
DNS_ASSERT( pname );
|
|
if ( pname )
|
|
{
|
|
pdomain = Dns_GetDomainNameW( pname );
|
|
if ( pdomain )
|
|
{
|
|
DNS_ASSERT( pdomain > pname+1 );
|
|
DNS_ASSERT( *(pdomain-1) == L'.' );
|
|
|
|
*(pdomain-1) = 0;
|
|
}
|
|
}
|
|
pblob->pHostent->h_aliases = NULL;
|
|
}
|
|
|
|
IF_DNSDBG( HOSTENT )
|
|
{
|
|
DnsDbg_HostentBlob(
|
|
"Leaving HostentBlob_CreateLocal():",
|
|
pblob );
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( status != NO_ERROR && pblob )
|
|
{
|
|
HostentBlob_Free( pblob );
|
|
pblob = NULL;
|
|
}
|
|
|
|
*ppBlob = pblob;
|
|
|
|
DNSDBG( HOSTENT, (
|
|
"Leave HostentBlob_CreateLocal() => status = %d\n",
|
|
status ));
|
|
|
|
return( status );
|
|
}
|
|
|
|
//
|
|
// End hostent.c
|
|
//
|
|
|
|
|