Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641/* * 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 *****************************************************************/
PVOIDWINAPIFlatBuf_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_BLOBWINAPISaBlob_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_BLOBWINAPISaBlob_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;}
VOIDWINAPISaBlob_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); }}
PHOSTENTWINAPISaBlob_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;}
INTWINAPISaBlob_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;}
INTWINAPISaBlob_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;}
BOOLEANWINAPISaBlob_IsSupportedAddrType(WORD DnsType){ /* Check for valid Types that we support */ return (DnsType == DNS_TYPE_A || DnsType == DNS_TYPE_ATMA || DnsType == DNS_TYPE_AAAA);}
INTWINAPISaBlob_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_BLOBWINAPISaBlob_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_BLOBWINAPISaBlob_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;}