|
|
/*++
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
//
|