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.
681 lines
21 KiB
681 lines
21 KiB
#include "dnsincs.h"
|
|
#include <stdlib.h>
|
|
|
|
extern void DeleteDnsRec(PSMTPDNS_RECS pDnsRec);
|
|
|
|
CAsyncMxDns::CAsyncMxDns(char *MyFQDN)
|
|
{
|
|
lstrcpyn(m_FQDNToDrop, MyFQDN, sizeof(m_FQDNToDrop));
|
|
m_fUsingMx = TRUE;
|
|
m_Index = 0;
|
|
m_LocalPref = 256;
|
|
m_SeenLocal = FALSE;
|
|
m_AuxList = NULL;
|
|
m_fMxLoopBack = FALSE;
|
|
|
|
ZeroMemory (m_Weight, sizeof(m_Weight));
|
|
ZeroMemory (m_Prefer, sizeof(m_Prefer));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Given a pDnsRec (array of host IP pairs) and an index into it, this
|
|
// tries to resolve the host at the Index position. It is assumed that
|
|
// the caller (GetMissingIpAddresses) has checked that the host at that
|
|
// index lacks an IP address.
|
|
// Arguments:
|
|
// IN PSMTPDNS_RECS pDnsRec --- Array of (host, IP) pairs.
|
|
// IN DWORD Index --- Index of host in pDnsRec to set IP for.
|
|
// Returns:
|
|
// TRUE --- Success IP was filled in for host.
|
|
// FALSE --- Either the host was not resolved from DNS or an error
|
|
// occurred (like "out of memory").
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CAsyncMxDns::GetIpFromDns(PSMTPDNS_RECS pDnsRec, DWORD Index)
|
|
{
|
|
MXIPLIST_ENTRY * pEntry = NULL;
|
|
BOOL fReturn = FALSE;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD rgdwIpAddresses[SMTP_MAX_DNS_ENTRIES];
|
|
DWORD cIpAddresses = SMTP_MAX_DNS_ENTRIES;
|
|
PIP_ARRAY pipDnsList = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMxDns::GetIpFromDns");
|
|
|
|
fReturn = GetDnsIpArrayCopy(&pipDnsList);
|
|
if(!fReturn)
|
|
{
|
|
ErrorTrace((LPARAM) this, "Unable to get DNS server list copy");
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return FALSE;
|
|
}
|
|
|
|
dwStatus = ResolveHost(
|
|
pDnsRec->DnsArray[Index]->DnsName,
|
|
pipDnsList,
|
|
DNS_QUERY_STANDARD,
|
|
rgdwIpAddresses,
|
|
&cIpAddresses);
|
|
|
|
if(dwStatus == ERROR_SUCCESS)
|
|
{
|
|
fReturn = TRUE;
|
|
for (DWORD Loop = 0; !IsShuttingDown() && Loop < cIpAddresses; Loop++)
|
|
{
|
|
pEntry = new MXIPLIST_ENTRY;
|
|
if(pEntry != NULL)
|
|
{
|
|
pDnsRec->DnsArray[Index]->NumEntries++;
|
|
CopyMemory(&pEntry->IpAddress, &rgdwIpAddresses[Loop], 4);
|
|
InsertTailList(&pDnsRec->DnsArray[Index]->IpListHead, &pEntry->ListEntry);
|
|
}
|
|
else
|
|
{
|
|
fReturn = FALSE;
|
|
ErrorTrace((LPARAM) this, "Not enough memory");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace((LPARAM) this, "gethostbyname failed on %s", pDnsRec->DnsArray[Index]->DnsName);
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
}
|
|
|
|
ReleaseDnsIpArray(pipDnsList);
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return fReturn;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// This runs through the list of hosts (MX hosts, or if no MX records were
|
|
// returned, the single target host) and verifies that they all have been
|
|
// resolved to IP addresses. If any have been found that do not have IP
|
|
// addresses, it will call GetIpFromDns to resolve it.
|
|
// Arguments:
|
|
// IN PSMTPDNS_RECS pDnsRec -- Object containing Host-IP pairs. Hosts
|
|
// without and IP are filled in.
|
|
// Returns:
|
|
// TRUE -- Success, all hosts have IP addresses.
|
|
// FALSE -- Unable to resolve all hosts to IP addresses, or some internal
|
|
// error occurred (like "out of memory" or "shutdown in progress".
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CAsyncMxDns::GetMissingIpAddresses(PSMTPDNS_RECS pDnsRec)
|
|
{
|
|
DWORD Count = 0;
|
|
DWORD Error = 0;
|
|
BOOL fSucceededOnce = FALSE;
|
|
|
|
if(pDnsRec == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
while(!IsShuttingDown() && pDnsRec->DnsArray[Count] != NULL)
|
|
{
|
|
if(IsListEmpty(&pDnsRec->DnsArray[Count]->IpListHead))
|
|
{
|
|
SetLastError(NO_ERROR);
|
|
if(!GetIpFromDns(pDnsRec, Count))
|
|
{
|
|
Error = GetLastError();
|
|
if(Error != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fSucceededOnce = TRUE;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
fSucceededOnce = TRUE;
|
|
}
|
|
|
|
|
|
Count++;
|
|
}
|
|
|
|
return ( fSucceededOnce );
|
|
|
|
}
|
|
|
|
int MxRand(char * host)
|
|
{
|
|
int hfunc = 0;
|
|
unsigned int seed = 0;;
|
|
|
|
seed = rand() & 0xffff;
|
|
|
|
hfunc = seed;
|
|
while (*host != '\0')
|
|
{
|
|
int c = *host++;
|
|
|
|
if (isascii((UCHAR)c) && isupper((UCHAR)c))
|
|
c = tolower(c);
|
|
|
|
hfunc = ((hfunc << 1) ^ c) % 2003;
|
|
}
|
|
|
|
hfunc &= 0xff;
|
|
|
|
return hfunc;
|
|
}
|
|
|
|
|
|
BOOL CAsyncMxDns::CheckList(void)
|
|
{
|
|
MXIPLIST_ENTRY * pEntry = NULL;
|
|
BOOL fRet = TRUE;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
DWORD rgdwIpAddresses[SMTP_MAX_DNS_ENTRIES];
|
|
DWORD cIpAddresses = SMTP_MAX_DNS_ENTRIES;
|
|
PIP_ARRAY pipDnsList = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncDns::CheckList");
|
|
|
|
if(m_Index == 0)
|
|
{
|
|
DebugTrace((LPARAM) this, "m_Index == 0 in CheckList");
|
|
|
|
m_fUsingMx = FALSE;
|
|
|
|
DeleteDnsRec(m_AuxList);
|
|
|
|
m_AuxList = new SMTPDNS_RECS;
|
|
if(m_AuxList == NULL)
|
|
{
|
|
ErrorTrace((LPARAM) this, "m_AuxList = new SMTPDNS_RECS failed");
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory(m_AuxList, sizeof(SMTPDNS_RECS));
|
|
|
|
m_AuxList->NumRecords = 1;
|
|
|
|
m_AuxList->DnsArray[0] = new MX_NAMES;
|
|
if(m_AuxList->DnsArray[0] == NULL)
|
|
{
|
|
ErrorTrace((LPARAM) this, "m_AuxList->DnsArray[0] = new MX_NAMES failed");
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return FALSE;
|
|
}
|
|
|
|
m_AuxList->DnsArray[0]->NumEntries = 0;
|
|
InitializeListHead(&m_AuxList->DnsArray[0]->IpListHead);
|
|
lstrcpyn(m_AuxList->DnsArray[0]->DnsName, m_HostName,
|
|
sizeof(m_AuxList->DnsArray[m_Index]->DnsName));
|
|
|
|
fRet = GetDnsIpArrayCopy(&pipDnsList);
|
|
if(!fRet)
|
|
{
|
|
ErrorTrace((LPARAM) this, "Unable to get DNS server list copy");
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return FALSE;
|
|
}
|
|
|
|
dwStatus = ResolveHost(
|
|
m_HostName,
|
|
pipDnsList,
|
|
DNS_QUERY_STANDARD,
|
|
rgdwIpAddresses,
|
|
&cIpAddresses);
|
|
|
|
if(dwStatus == ERROR_SUCCESS && cIpAddresses)
|
|
{
|
|
for (DWORD Loop = 0; Loop < cIpAddresses; Loop++)
|
|
{
|
|
pEntry = new MXIPLIST_ENTRY;
|
|
if(pEntry != NULL)
|
|
{
|
|
m_AuxList->DnsArray[0]->NumEntries++;
|
|
CopyMemory(&pEntry->IpAddress, &rgdwIpAddresses[Loop], 4);
|
|
InsertTailList(&m_AuxList->DnsArray[0]->IpListHead, &pEntry->ListEntry);
|
|
}
|
|
else
|
|
{
|
|
fRet = FALSE;
|
|
ErrorTrace((LPARAM) this, "pEntry = new MXIPLIST_ENTRY failed in CheckList");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fRet = FALSE;
|
|
}
|
|
|
|
ReleaseDnsIpArray(pipDnsList);
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return fRet;
|
|
}
|
|
|
|
BOOL CAsyncMxDns::SortMxList(void)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
/* sort the records */
|
|
for (DWORD i = 0; i < m_Index; i++)
|
|
{
|
|
for (DWORD j = i + 1; j < m_Index; j++)
|
|
{
|
|
if (m_Prefer[i] > m_Prefer[j] ||
|
|
(m_Prefer[i] == m_Prefer[j] && m_Weight[i] > m_Weight[j]))
|
|
{
|
|
DWORD temp;
|
|
MX_NAMES *temp1;
|
|
|
|
temp = m_Prefer[i];
|
|
m_Prefer[i] = m_Prefer[j];
|
|
m_Prefer[j] = temp;
|
|
temp1 = m_AuxList->DnsArray[i];
|
|
m_AuxList->DnsArray[i] = m_AuxList->DnsArray[j];
|
|
m_AuxList->DnsArray[j] = temp1;
|
|
temp = m_Weight[i];
|
|
m_Weight[i] = m_Weight[j];
|
|
m_Weight[j] = temp;
|
|
}
|
|
}
|
|
|
|
if (m_SeenLocal && m_Prefer[i] >= m_LocalPref)
|
|
{
|
|
/* truncate higher preference part of list */
|
|
m_Index = i;
|
|
}
|
|
}
|
|
|
|
m_AuxList->NumRecords = m_Index;
|
|
|
|
if(!CheckList())
|
|
{
|
|
DeleteDnsRec(m_AuxList);
|
|
m_AuxList = NULL;
|
|
fRet = FALSE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
void CAsyncMxDns::ProcessMxRecord(PDNS_RECORD pnewRR)
|
|
{
|
|
DWORD Len = 0;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncDns::ProcessMxRecord");
|
|
|
|
//
|
|
// Leave room for NULL-termination of array
|
|
//
|
|
if(m_Index >= SMTP_MAX_DNS_ENTRIES-1)
|
|
{
|
|
DebugTrace((LPARAM) this, "SMTP_MAX_DNS_ENTRIES reached for %s", m_HostName);
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return;
|
|
}
|
|
|
|
if((pnewRR->wType == DNS_TYPE_MX) && pnewRR->Data.MX.nameExchange)
|
|
{
|
|
Len = lstrlen(pnewRR->Data.MX.nameExchange);
|
|
if(pnewRR->Data.MX.nameExchange[Len - 1] == '.')
|
|
{
|
|
pnewRR->Data.MX.nameExchange[Len - 1] = '\0';
|
|
}
|
|
|
|
DebugTrace((LPARAM) this, "Received MX rec %s with priority %d for %s", pnewRR->Data.MX.nameExchange, pnewRR->Data.MX.wPreference, m_HostName);
|
|
|
|
if(lstrcmpi(pnewRR->Data.MX.nameExchange, m_FQDNToDrop))
|
|
{
|
|
m_AuxList->DnsArray[m_Index] = new MX_NAMES;
|
|
|
|
if(m_AuxList->DnsArray[m_Index])
|
|
{
|
|
m_AuxList->DnsArray[m_Index]->NumEntries = 0;;
|
|
InitializeListHead(&m_AuxList->DnsArray[m_Index]->IpListHead);
|
|
lstrcpyn(m_AuxList->DnsArray[m_Index]->DnsName,pnewRR->Data.MX.nameExchange, sizeof(m_AuxList->DnsArray[m_Index]->DnsName));
|
|
m_Weight[m_Index] = MxRand (m_AuxList->DnsArray[m_Index]->DnsName);
|
|
m_Prefer[m_Index] = pnewRR->Data.MX.wPreference;
|
|
m_Index++;
|
|
}
|
|
else
|
|
{
|
|
DebugTrace((LPARAM) this, "Out of memory allocating MX_NAMES for %s", m_HostName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!m_SeenLocal || pnewRR->Data.MX.wPreference < m_LocalPref)
|
|
m_LocalPref = pnewRR->Data.MX.wPreference;
|
|
|
|
m_SeenLocal = TRUE;
|
|
}
|
|
}
|
|
else if(pnewRR->wType == DNS_TYPE_A)
|
|
{
|
|
MXIPLIST_ENTRY * pEntry = NULL;
|
|
|
|
for(DWORD i = 0; i < m_Index; i++)
|
|
{
|
|
if(lstrcmpi(pnewRR->nameOwner, m_AuxList->DnsArray[i]->DnsName) == 0)
|
|
{
|
|
pEntry = new MXIPLIST_ENTRY;
|
|
|
|
if(pEntry != NULL)
|
|
{
|
|
m_AuxList->DnsArray[i]->NumEntries++;;
|
|
pEntry->IpAddress = pnewRR->Data.A.ipAddress;
|
|
InsertTailList(&m_AuxList->DnsArray[i]->IpListHead, &pEntry->ListEntry);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
}
|
|
|
|
void CAsyncMxDns::ProcessARecord(PDNS_RECORD pnewRR)
|
|
{
|
|
MXIPLIST_ENTRY * pEntry = NULL;
|
|
|
|
if(pnewRR->wType == DNS_TYPE_A)
|
|
{
|
|
pEntry = new MXIPLIST_ENTRY;
|
|
|
|
if(pEntry != NULL)
|
|
{
|
|
pEntry->IpAddress = pnewRR->Data.A.ipAddress;
|
|
InsertTailList(&m_AuxList->DnsArray[0]->IpListHead, &pEntry->ListEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Checks to see if any of the IP addresses returned by DNS belong to this
|
|
// machine. This is a common configuration when there are backup mail
|
|
// spoolers. To avoid mail looping, we should delete all MX records that
|
|
// are less preferred than the record containing the local IP address.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
// Returns:
|
|
// TRUE if no loopback
|
|
// FALSE if loopback detected
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CAsyncMxDns::CheckMxLoopback()
|
|
{
|
|
ULONG i = 0;
|
|
ULONG cLocalIndex = 0;
|
|
BOOL fSeenLocal = TRUE;
|
|
DWORD dwIpAddress = INADDR_NONE;
|
|
DWORD dwLocalPref = 256;
|
|
PLIST_ENTRY pListHead = NULL;
|
|
PLIST_ENTRY pListTail = NULL;
|
|
PLIST_ENTRY pListCurrent = NULL;
|
|
PMXIPLIST_ENTRY pMxIpListEntry = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM)this, "CAsyncMxDns::CheckMxLoopback");
|
|
|
|
if(!m_AuxList)
|
|
{
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// m_AuxList is a sorted list of MX records. Scan through it searching
|
|
// for an MX record with a local-IP address. cLocalIndex is set to the
|
|
// index, within m_AuxList, of this record.
|
|
//
|
|
|
|
while(m_AuxList->DnsArray[cLocalIndex] != NULL)
|
|
{
|
|
pListTail = &(m_AuxList->DnsArray[cLocalIndex]->IpListHead);
|
|
pListHead = m_AuxList->DnsArray[cLocalIndex]->IpListHead.Flink;
|
|
pListCurrent = pListHead;
|
|
|
|
while(pListCurrent != pListTail)
|
|
{
|
|
pMxIpListEntry = CONTAINING_RECORD(pListCurrent, MXIPLIST_ENTRY, ListEntry);
|
|
dwIpAddress = pMxIpListEntry->IpAddress;
|
|
|
|
if(IsAddressMine(dwIpAddress))
|
|
{
|
|
DNS_PRINTF_MSG("Local host's IP is one of the target IPs.\n");
|
|
DNS_PRINTF_MSG("Discarding all equally or less-preferred IP addresses.\n");
|
|
|
|
DebugTrace((LPARAM)this, "Local record found in MX list, name=%s, pref=%d, ip=%08x",
|
|
m_AuxList->DnsArray[cLocalIndex]->DnsName,
|
|
m_Prefer[cLocalIndex],
|
|
dwIpAddress);
|
|
|
|
// All records with preference > m_Prefer[cLocalIndex] should be deleted. Since
|
|
// m_AuxList is sorted by preference, we need to delete everthing with index >
|
|
// cLocalIndex. However since there may be some records with preference == local-
|
|
// preference, which occur before cLocalIndex, we walk backwards till we find
|
|
// the first record with preference = m_Prefer[cLocalIndex].
|
|
|
|
dwLocalPref = m_Prefer[cLocalIndex];
|
|
|
|
while(cLocalIndex > 0 && dwLocalPref == m_Prefer[cLocalIndex])
|
|
cLocalIndex--;
|
|
|
|
if(dwLocalPref != m_Prefer[cLocalIndex])
|
|
cLocalIndex++;
|
|
|
|
fSeenLocal = TRUE;
|
|
|
|
// All records > cLocalIndex are even less preferred than this one,
|
|
// (since m_AuxList already sorted) and will be deleted.
|
|
goto END_SEARCH;
|
|
}
|
|
|
|
pListCurrent = pListCurrent->Flink;
|
|
}
|
|
|
|
cLocalIndex++;
|
|
}
|
|
|
|
END_SEARCH:
|
|
//
|
|
// If a local-IP address was found, delete all less-preferred records
|
|
//
|
|
if(fSeenLocal)
|
|
{
|
|
DebugTrace((LPARAM)this,
|
|
"Deleting all MX records with lower preference than %d", m_Prefer[cLocalIndex]);
|
|
|
|
for(i = cLocalIndex; m_AuxList->DnsArray[i] != NULL; i++)
|
|
{
|
|
if(!m_AuxList->DnsArray[i]->DnsName[0])
|
|
continue;
|
|
|
|
while(!IsListEmpty(&(m_AuxList->DnsArray[i]->IpListHead)))
|
|
{
|
|
pListCurrent = RemoveHeadList(&(m_AuxList->DnsArray[i]->IpListHead));
|
|
pMxIpListEntry = CONTAINING_RECORD(pListCurrent, MXIPLIST_ENTRY, ListEntry);
|
|
delete pMxIpListEntry;
|
|
}
|
|
|
|
delete m_AuxList->DnsArray[i];
|
|
m_AuxList->DnsArray[i] = NULL;
|
|
}
|
|
m_AuxList->NumRecords = cLocalIndex;
|
|
|
|
// No records left
|
|
if(m_AuxList->NumRecords == 0)
|
|
{
|
|
DNS_PRINTF_ERR("DNS configuration error (loopback), messages will be NDRed.\n");
|
|
DNS_PRINTF_ERR("Local host's IP address is the most preferred MX record.\n");
|
|
|
|
ErrorTrace((LPARAM)this, "Possible misconfiguration: most preferred MX record is loopback");
|
|
_ASSERT(m_AuxList->pMailMsgObj == NULL);
|
|
delete m_AuxList;
|
|
m_AuxList = NULL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
TraceFunctLeaveEx((LPARAM)this);
|
|
return TRUE;
|
|
}
|
|
|
|
void CAsyncMxDns::DnsProcessReply(
|
|
DWORD status,
|
|
PDNS_RECORD pRecordList)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncDns::DnsParseMessage");
|
|
PDNS_RECORD pTmp = NULL;
|
|
|
|
m_SeenLocal = FALSE;
|
|
m_LocalPref = 256;
|
|
|
|
m_AuxList = new SMTPDNS_RECS;
|
|
if(!m_AuxList)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ZeroMemory(m_AuxList, sizeof(SMTPDNS_RECS));
|
|
|
|
//
|
|
// Due to Raid #122555 m_fUsingMx is always TRUE in this function
|
|
// - hence we will always go a GetHostByName() if there is no MX
|
|
// record. It would be better Perf if we did a A record lookup.
|
|
//
|
|
DebugTrace((LPARAM) this, "Parsed DNS record for %s. status = 0x%08x", m_HostName, status);
|
|
|
|
switch(status)
|
|
{
|
|
case ERROR_SUCCESS:
|
|
//
|
|
// Got the DNS record we want.
|
|
//
|
|
DNS_PRINTF_MSG("Processing MX/A records in reply.\n");
|
|
|
|
DebugTrace((LPARAM) this, "Success: DNS record parsed");
|
|
pTmp = pRecordList;
|
|
while( pTmp )
|
|
{
|
|
if( m_fUsingMx )
|
|
{
|
|
ProcessMxRecord( pTmp );
|
|
}
|
|
else
|
|
{
|
|
ProcessARecord( pTmp );
|
|
}
|
|
pTmp = pTmp->pNext;
|
|
}
|
|
|
|
if(m_fUsingMx)
|
|
{
|
|
//
|
|
// SortMxList sorts the MX records by preference and calls
|
|
// gethostbyname() to resolve A records for Mail Exchangers
|
|
// if needed (when the A records are not returned in the
|
|
// supplementary info).
|
|
//
|
|
|
|
DNS_PRINTF_MSG("Sorting MX records by priority.\n");
|
|
if(SortMxList())
|
|
{
|
|
status = ERROR_SUCCESS;
|
|
DebugTrace((LPARAM) this, "SortMxList() succeeded.");
|
|
}
|
|
else
|
|
{
|
|
status = ERROR_RETRY;
|
|
ErrorTrace((LPARAM) this, "SortMxList() failed. Message will stay queued.");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DNS_ERROR_RCODE_NAME_ERROR:
|
|
// Fall through to using gethostbyname()
|
|
|
|
case DNS_INFO_NO_RECORDS:
|
|
// Non authoritative host not found.
|
|
// Fall through to using gethostbyname()
|
|
|
|
default:
|
|
DebugTrace((LPARAM) this, "Error in query: status = 0x%08x.", status);
|
|
|
|
//
|
|
// Use gethostbyname to resolve the hostname:
|
|
// One issue with our approach is that sometimes we will NDR the message
|
|
// on non-permanent errors, "like WINS server down", when gethostbyname
|
|
// fails. However, there's no way around it --- gethostbyname doesn't
|
|
// report errors in a reliable manner, so it's not possible to distinguish
|
|
// between permanent and temporary errors.
|
|
//
|
|
|
|
if (!CheckList ()) {
|
|
|
|
if(status == DNS_ERROR_RCODE_NAME_ERROR) {
|
|
|
|
DNS_PRINTF_ERR("Host does not exist in DNS. Messages will be NDRed.\n");
|
|
ErrorTrace((LPARAM) this, "Authoritative error");
|
|
status = ERROR_NOT_FOUND;
|
|
} else {
|
|
|
|
DNS_PRINTF_ERR("Host could not be resolved. Messages will be retried later.\n");
|
|
ErrorTrace((LPARAM) this, "Retryable error");
|
|
status = ERROR_RETRY;
|
|
}
|
|
|
|
} else {
|
|
|
|
DebugTrace ((LPARAM) this, "Successfully resolved using gethostbyname");
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make a last ditch effort to fill in the IP addresses for any hosts
|
|
// that are still unresolved.
|
|
//
|
|
|
|
if(m_AuxList && status == ERROR_SUCCESS)
|
|
{
|
|
if(!GetMissingIpAddresses(m_AuxList))
|
|
{
|
|
DeleteDnsRec(m_AuxList);
|
|
m_AuxList = NULL;
|
|
status = ERROR_RETRY;
|
|
goto Exit;
|
|
}
|
|
|
|
if(!CheckMxLoopback())
|
|
{
|
|
m_fMxLoopBack = TRUE;
|
|
DeleteDnsRec(m_AuxList);
|
|
m_AuxList = NULL;
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// End of resolve: HandleCompleted data examines the DnsStatus and results, and sets up
|
|
// member variables of CAsyncMxDns to either NDR messages, connect to the remote host
|
|
// or ack this queue for retry when the object is deleted.
|
|
//
|
|
Exit:
|
|
HandleCompletedData(status);
|
|
return;
|
|
}
|