+++ /dev/null
-/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS DNS Shared Library
- * FILE: lib/dnslib/sablob.c
- * PURPOSE: Functions for the Saved Answer Blob Implementation
- */
-
-/* INCLUDES ******************************************************************/
-#include "precomp.h"
-
-/* DATA **********************************************************************/
-
-/* FUNCTIONS *****************************************************************/
-
-PVOID
-WINAPI
-FlatBuf_Arg_ReserveAlignPointer(IN PVOID Position,
- IN PSIZE_T FreeSize,
- IN SIZE_T Size)
-{
- /* Just a little helper that we use */
- return FlatBuf_Arg_Reserve(Position, FreeSize, Size, sizeof(PVOID));
-}
-
-PDNS_BLOB
-WINAPI
-SaBlob_Create(IN ULONG Count)
-{
- PDNS_BLOB Blob;
- PDNS_ARRAY DnsAddrArray;
-
- /* Allocate the blob */
- Blob = Dns_AllocZero(sizeof(DNS_BLOB));
- if (Blob)
- {
- /* Check if it'll hold any addresses */
- if (Count)
- {
- /* Create the DNS Address Array */
- DnsAddrArray = DnsAddrArray_Create(Count);
- if (!DnsAddrArray)
- {
- /* Failure, free the blob */
- SaBlob_Free(Blob);
- SetLastError(ERROR_OUTOFMEMORY);
- }
- else
- {
- /* Link it with the blob */
- Blob->DnsAddrArray = DnsAddrArray;
- }
- }
- }
-
- /* Return the blob */
- return Blob;
-}
-
-PDNS_BLOB
-WINAPI
-SaBlob_CreateFromIp4(IN LPWSTR Name,
- IN ULONG Count,
- IN PIN_ADDR AddressArray)
-{
- PDNS_BLOB Blob;
- LPWSTR NameCopy;
- ULONG i;
-
- /* Create the blob */
- Blob = SaBlob_Create(Count);
- if (!Blob) goto Quickie;
-
- /* If we have a name */
- if (Name)
- {
- /* Create a copy of it */
- NameCopy = Dns_CreateStringCopy_W(Name);
- if (!NameCopy) goto Quickie;
-
- /* Save the pointer to the name */
- Blob->Name = NameCopy;
- }
-
- /* Loop all the addresses */
- for (i = 0; i < Count; i++)
- {
- /* Add an entry for this address */
- DnsAddrArray_AddIp4(Blob->DnsAddrArray, AddressArray[i], IpV4Address);
- }
-
- /* Return the blob */
- return Blob;
-
-Quickie:
- /* Free the blob, set error and fail */
- SaBlob_Free(Blob);
- SetLastError(ERROR_OUTOFMEMORY);
- return NULL;
-}
-
-VOID
-WINAPI
-SaBlob_Free(IN PDNS_BLOB Blob)
-{
- /* Make sure we got a blob */
- if (Blob)
- {
- /* Free the name */
- Dns_Free(Blob->Name);
-
- /* Loop the aliases */
- while (Blob->AliasCount)
- {
- /* Free the alias */
- Dns_Free(Blob->Aliases[Blob->AliasCount]);
-
- /* Decrease number of aliases */
- Blob->AliasCount--;
- }
-
- /* Free the DNS Address Array */
- DnsAddrArray_Free(Blob->DnsAddrArray);
-
- /* Free the blob itself */
- Dns_Free(Blob);
- }
-}
-
-PHOSTENT
-WINAPI
-SaBlob_CreateHostent(IN OUT PULONG_PTR BufferPosition,
- IN OUT PSIZE_T FreeBufferSpace,
- IN OUT PSIZE_T HostEntrySize,
- IN PDNS_BLOB Blob,
- IN DWORD StringType,
- IN BOOLEAN Relative,
- IN BOOLEAN BufferAllocated)
-{
- PDNS_ARRAY DnsAddrArray = Blob->DnsAddrArray;
- ULONG AliasCount = Blob->AliasCount;
- WORD AddressFamily = AF_UNSPEC;
- ULONG AddressCount = 0, AddressSize = 0, TotalSize, NamePointerSize;
- ULONG AliasPointerSize;
- PDNS_FAMILY_INFO FamilyInfo = NULL;
- ULONG StringLength = 0;
- ULONG i;
- ULONG HostentSize = 0;
- PHOSTENT Hostent = NULL;
- ULONG_PTR HostentPtr;
- PVOID CurrentAddress;
-
- /* Check if we actually have any addresses */
- if (DnsAddrArray)
- {
- /* Get the address family */
- AddressFamily = DnsAddrArray->Addresses[0].AddressFamily;
-
- /* Get family information */
- FamilyInfo = FamilyInfo_GetForFamily(AddressFamily);
-
- /* Save the current address count and their size */
- AddressCount = DnsAddrArray->UsedAddresses;
- AddressSize = FamilyInfo->AddressSize;
- }
-
- /* Calculate total size for all the addresses, and their pointers */
- TotalSize = AddressSize * AddressCount;
- NamePointerSize = AddressCount * sizeof(PVOID) + sizeof(PVOID);
-
- /* Check if we have a name */
- if (Blob->Name)
- {
- /* Find out the size we'll need for a copy */
- StringLength = (Dns_GetBufferLengthForStringCopy(Blob->Name,
- 0,
- UnicodeString,
- StringType) + 1) & ~1;
- }
-
- /* Now do the same for the aliases */
- for (i = AliasCount; i; i--)
- {
- /* Find out the size we'll need for a copy */
- HostentSize += (Dns_GetBufferLengthForStringCopy(Blob->Aliases[i],
- 0,
- UnicodeString,
- StringType) + 1) & ~1;
- }
-
- /* Find out how much the pointers will take */
- AliasPointerSize = AliasCount * sizeof(PVOID) + sizeof(PVOID);
-
- /* Calculate Hostent Size */
- HostentSize += TotalSize +
- NamePointerSize +
- AliasPointerSize +
- StringLength +
- sizeof(HOSTENT);
-
- /* Check if we already have a buffer */
- if (!BufferAllocated)
- {
- /* We don't, allocate space ourselves */
- HostentPtr = (ULONG_PTR)Dns_AllocZero(HostentSize);
- }
- else
- {
- /* We do, so allocate space in the buffer */
- HostentPtr = (ULONG_PTR)FlatBuf_Arg_ReserveAlignPointer(BufferPosition,
- FreeBufferSpace,
- HostentSize);
- }
-
- /* Make sure we got space */
- if (HostentPtr)
- {
- /* Initialize it */
- Hostent = Hostent_Init((PVOID)&HostentPtr,
- AddressFamily,
- AddressSize,
- AddressCount,
- AliasCount);
- }
-
- /* Loop the addresses */
- for (i = 0; i < AddressCount; i++)
- {
- /* Get the pointer of the current address */
- CurrentAddress = (PVOID)((ULONG_PTR)&DnsAddrArray->Addresses[i] +
- FamilyInfo->AddressOffset);
-
- /* Write the pointer */
- Hostent->h_addr_list[i] = (PCHAR)HostentPtr;
-
- /* Copy the address */
- RtlCopyMemory((PVOID)HostentPtr, CurrentAddress, AddressSize);
-
- /* Advance the buffer */
- HostentPtr += AddressSize;
- }
-
- /* Check if we have a name */
- if (Blob->Name)
- {
- /* Align our current position */
- HostentPtr += 1 & ~1;
-
- /* Save our name here */
- Hostent->h_name = (LPSTR)HostentPtr;
-
- /* Now copy it in the blob */
- HostentPtr += Dns_StringCopy((PVOID)HostentPtr,
- NULL,
- Blob->Name,
- 0,
- UnicodeString,
- StringType);
- }
-
- /* Loop the Aliases */
- for (i = AliasCount; i; i--)
- {
- /* Align our current position */
- HostentPtr += 1 & ~1;
-
- /* Save our alias here */
- Hostent->h_aliases[i] = (LPSTR)HostentPtr;
-
- /* Now copy it in the blob */
- HostentPtr += Dns_StringCopy((PVOID)HostentPtr,
- NULL,
- Blob->Aliases[i],
- 0,
- UnicodeString,
- StringType);
- }
-
- /* Check if the caller didn't have a buffer */
- if (!BufferAllocated)
- {
- /* Return the size; not needed if we had a blob, since it's internal */
- *HostEntrySize = *BufferPosition - (ULONG_PTR)HostentPtr;
- }
-
- /* Convert to Offsets if requested */
- if(Relative) Hostent_ConvertToOffsets(Hostent);
-
- /* Return the full, complete, hostent */
- return Hostent;
-}
-
-INT
-WINAPI
-SaBlob_WriteNameOrAlias(IN PDNS_BLOB Blob,
- IN LPWSTR String,
- IN BOOLEAN IsAlias)
-{
- /* Check if this is an alias */
- if (!IsAlias)
- {
- /* It's not. Simply create a copy of the string */
- Blob->Name = Dns_CreateStringCopy_W(String);
- if (!Blob->Name) return GetLastError();
- }
- else
- {
- /* Does it have a name, and less then 8 aliases? */
- if ((Blob->Name) && (Blob->AliasCount <= 8))
- {
- /* Yup, create a copy of the string and increase the alias count */
- Blob->Aliases[Blob->AliasCount] = Dns_CreateStringCopy_W(String);
- Blob->AliasCount++;
- }
- else
- {
- /* Invalid request! */
- return ERROR_MORE_DATA;
- }
- }
-
- /* Return Success */
- return ERROR_SUCCESS;
-}
-
-INT
-WINAPI
-SaBlob_WriteAddress(IN PDNS_BLOB Blob,
- OUT PDNS_ADDRESS DnsAddr)
-{
- /* Check if we have an array yet */
- if (!Blob->DnsAddrArray)
- {
- /* Allocate one! */
- Blob->DnsAddrArray = DnsAddrArray_Create(1);
- if (!Blob->DnsAddrArray) return ERROR_OUTOFMEMORY;
- }
-
- /* Add this address */
- return DnsAddrArray_AddAddr(Blob->DnsAddrArray, DnsAddr, AF_UNSPEC, 0) ?
- ERROR_SUCCESS:
- ERROR_MORE_DATA;
-}
-
-BOOLEAN
-WINAPI
-SaBlob_IsSupportedAddrType(WORD DnsType)
-{
- /* Check for valid Types that we support */
- return (DnsType == DNS_TYPE_A ||
- DnsType == DNS_TYPE_ATMA ||
- DnsType == DNS_TYPE_AAAA);
-}
-
-INT
-WINAPI
-SaBlob_WriteRecords(OUT PDNS_BLOB Blob,
- IN PDNS_RECORD DnsRecord,
- IN BOOLEAN DoAlias)
-{
- DNS_ADDRESS DnsAddress;
- INT ErrorCode = STATUS_INVALID_PARAMETER;
- BOOLEAN WroteOnce = FALSE;
-
- /* Zero out the Address */
- RtlZeroMemory(&DnsAddress, sizeof(DnsAddress));
-
- /* Loop through all the Records */
- while (DnsRecord)
- {
- /* Is this not an answer? */
- if (DnsRecord->Flags.S.Section != DNSREC_ANSWER)
- {
- /* Then simply move on to the next DNS Record */
- DnsRecord = DnsRecord->pNext;
- continue;
- }
-
- /* Check the type of thsi record */
- switch(DnsRecord->wType)
- {
- /* Regular IPv4, v6 or ATM Record */
- case DNS_TYPE_A:
- case DNS_TYPE_AAAA:
- case DNS_TYPE_ATMA:
-
- /* Create a DNS Address from the record */
- DnsAddr_BuildFromDnsRecord(DnsRecord, &DnsAddress);
-
- /* Add it to the DNS Blob */
- ErrorCode = SaBlob_WriteAddress(Blob, &DnsAddress);
-
- /* Add the name, if needed */
- if ((DoAlias) &&
- (!WroteOnce) &&
- (!Blob->Name) &&
- (DnsRecord->pName))
- {
- /* Write the name from the DNS Record */
- ErrorCode = SaBlob_WriteNameOrAlias(Blob,
- DnsRecord->pName,
- FALSE);
- WroteOnce = TRUE;
- }
- break;
-
- case DNS_TYPE_CNAME:
-
- /* Just write the alias name */
- ErrorCode = SaBlob_WriteNameOrAlias(Blob,
- DnsRecord->pName,
- TRUE);
- break;
-
- case DNS_TYPE_PTR:
-
- /* Check if we already have a name */
- if (Blob->Name)
- {
- /* We don't, so add this as a name */
- ErrorCode = SaBlob_WriteNameOrAlias(Blob,
- DnsRecord->pName,
- FALSE);
- }
- else
- {
- /* We do, so add it as an alias */
- ErrorCode = SaBlob_WriteNameOrAlias(Blob,
- DnsRecord->pName,
- TRUE);
- }
- break;
- default:
- break;
- }
-
- /* Next record */
- DnsRecord = DnsRecord->pNext;
- }
-
- /* Return error code */
- return ErrorCode;
-}
-
-PDNS_BLOB
-WINAPI
-SaBlob_CreateFromRecords(IN PDNS_RECORD DnsRecord,
- IN BOOLEAN DoAliases,
- IN DWORD DnsType)
-{
- PDNS_RECORD LocalDnsRecord;
- ULONG ProcessedCount = 0;
- PDNS_BLOB DnsBlob;
- INT ErrorCode;
- DNS_ADDRESS DnsAddress;
-
- /* Find out how many DNS Addresses to allocate */
- LocalDnsRecord = DnsRecord;
- while (LocalDnsRecord)
- {
- /* Make sure this record is an answer */
- if ((LocalDnsRecord->Flags.S.Section == DNSREC_ANSWER) &&
- (SaBlob_IsSupportedAddrType(LocalDnsRecord->wType)))
- {
- /* Increase number of records to process */
- ProcessedCount++;
- }
-
- /* Move to the next record */
- LocalDnsRecord = LocalDnsRecord->pNext;
- }
-
- /* Create the DNS Blob */
- DnsBlob = SaBlob_Create(ProcessedCount);
- if (!DnsBlob)
- {
- /* Fail */
- ErrorCode = GetLastError();
- goto Quickie;
- }
-
- /* Write the record to the DNS Blob */
- ErrorCode = SaBlob_WriteRecords(DnsBlob, DnsRecord, TRUE);
- if (ErrorCode != NO_ERROR)
- {
- /* We failed... but do we still have valid data? */
- if ((DnsBlob->Name) || (DnsBlob->AliasCount))
- {
- /* We'll just assume success then */
- ErrorCode = NO_ERROR;
- }
- else
- {
- /* Ok, last chance..do you have a DNS Address Array? */
- if ((DnsBlob->DnsAddrArray) &&
- (DnsBlob->DnsAddrArray->UsedAddresses))
- {
- /* Boy are you lucky! */
- ErrorCode = NO_ERROR;
- }
- }
-
- /* Buh-bye! */
- goto Quickie;
- }
-
- /* Check if this is a PTR record */
- if ((DnsRecord->wType == DNS_TYPE_PTR) ||
- ((DnsType == DNS_TYPE_PTR) &&
- (DnsRecord->wType == DNS_TYPE_CNAME) &&
- (DnsRecord->Flags.S.Section == DNSREC_ANSWER)))
- {
- /* Get a DNS Address Structure */
- if (Dns_ReverseNameToDnsAddr_W(&DnsAddress, DnsRecord->pName))
- {
- /* Add it to the Blob */
- if (SaBlob_WriteAddress(DnsBlob, &DnsAddress)) ErrorCode = NO_ERROR;
- }
- }
-
- /* Ok...do we still not have a name? */
- if (!(DnsBlob->Name) && (DoAliases) && (LocalDnsRecord))
- {
- /* We have an local DNS Record, so just use it to write the name */
- ErrorCode = SaBlob_WriteNameOrAlias(DnsBlob,
- LocalDnsRecord->pName,
- FALSE);
- }
-
-Quickie:
- /* Check error code */
- if (ErrorCode != NO_ERROR)
- {
- /* Free the blob and set the error */
- SaBlob_Free(DnsBlob);
- DnsBlob = NULL;
- SetLastError(ErrorCode);
- }
-
- /* Return */
- return DnsBlob;
-}
-
-PDNS_BLOB
-WINAPI
-SaBlob_Query(IN LPWSTR Name,
- IN WORD DnsType,
- IN ULONG Flags,
- IN PVOID *Reserved,
- IN DWORD AddressFamily)
-{
- PDNS_RECORD DnsRecord = NULL;
- INT ErrorCode;
- PDNS_BLOB DnsBlob = NULL;
- LPWSTR LocalName, LocalNameCopy;
-
- /* If they want reserved data back, clear it out in case we fail */
- if (Reserved) *Reserved = NULL;
-
- /* Query DNS */
- ErrorCode = DnsQuery_W(Name,
- DnsType,
- Flags,
- NULL,
- &DnsRecord,
- Reserved);
- if (ErrorCode != ERROR_SUCCESS)
- {
- /* We failed... did the caller use reserved data? */
- if (Reserved && *Reserved)
- {
- /* He did, and it was valid. Free it */
- DnsApiFree(*Reserved);
- *Reserved = NULL;
- }
-
- /* Normalize error code */
- if (ErrorCode == RPC_S_SERVER_UNAVAILABLE) ErrorCode = WSATRY_AGAIN;
- goto Quickie;
- }
-
- /* Now create the Blob from the DNS Records */
- DnsBlob = SaBlob_CreateFromRecords(DnsRecord, TRUE, DnsType);
- if (!DnsBlob)
- {
- /* Failed, get error code */
- ErrorCode = GetLastError();
- goto Quickie;
- }
-
- /* Make sure it has a name */
- if (!DnsBlob->Name)
- {
- /* It doesn't, fail */
- ErrorCode = DNS_INFO_NO_RECORDS;
- goto Quickie;
- }
-
- /* Check if the name is local or loopback */
- if (!(DnsNameCompare_W(DnsBlob->Name, L"localhost")) &&
- !(DnsNameCompare_W(DnsBlob->Name, L"loopback")))
- {
- /* Nothing left to do, exit! */
- goto Quickie;
- }
-
- /* This is a local name...query it */
- LocalName = DnsQueryConfigAllocEx(DnsConfigFullHostName_W, NULL, NULL);
- if (LocalName)
- {
- /* Create a copy for the caller */
- LocalNameCopy = Dns_CreateStringCopy_W(LocalName);
- if (LocalNameCopy)
- {
- /* Overwrite the one in the blob */
- DnsBlob->Name = LocalNameCopy;
- }
- else
- {
- /* We failed to make a copy, free memory */
- DnsApiFree(LocalName);
- }
- }
-
-Quickie:
- /* Free the DNS Record if we have one */
- if (DnsRecord) DnsRecordListFree(DnsRecord, DnsFreeRecordList);
-
- /* Check if this is a failure path with an active blob */
- if ((ErrorCode != ERROR_SUCCESS) && (DnsBlob))
- {
- /* Free the blob */
- SaBlob_Free(DnsBlob);
- DnsBlob = NULL;
- }
-
- /* Set the last error and return */
- SetLastError(ErrorCode);
- return DnsBlob;
-}
-