mirror of https://github.com/lianthony/NT4.0
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.
1019 lines
25 KiB
1019 lines
25 KiB
/*++
|
|
|
|
Copyright (c) 1989-1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
DNS.c
|
|
|
|
Abstract:
|
|
|
|
VxD-specific DNS routines.
|
|
|
|
This stuff will all be obsolete when we get proper services for
|
|
Windows. Then we will just call Winsock for DNS name resolution.
|
|
|
|
Author:
|
|
|
|
Earle R. Horton (ERH) 13-Feb-1996
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "nbtprocs.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
ULONG
|
|
DoDnsResolveDirect(
|
|
PNCB pncb,
|
|
PUCHAR pzDnsName,
|
|
PULONG pIpAddress
|
|
)
|
|
{
|
|
PDNS_DIRECT_WORK_ITEM_CONTEXT pContext;
|
|
PUCHAR pch;
|
|
tDEVICECONTEXT *pDeviceContext;
|
|
ULONG status;
|
|
CTELockHandle OldIrq;
|
|
|
|
pDeviceContext = GetDeviceContext( pncb ) ;
|
|
|
|
if ( pDeviceContext == NULL )
|
|
{
|
|
return NRC_BRIDGE ;
|
|
}
|
|
|
|
//
|
|
// If the primary DNS server is not defined, just return error.
|
|
// Return command timed out here.
|
|
//
|
|
if ( (!pDeviceContext->lDnsServerAddress) ||
|
|
( pDeviceContext->lDnsServerAddress == LOOP_BACK) )
|
|
{
|
|
return( NRC_NOCALL );
|
|
}
|
|
|
|
pContext = CTEAllocMem( sizeof(DNS_DIRECT_WORK_ITEM_CONTEXT) );
|
|
|
|
if ( pContext == NULL )
|
|
{
|
|
return NRC_NORESOURCES;
|
|
}
|
|
|
|
CTEZeroMemory( pContext, sizeof(DNS_DIRECT_WORK_ITEM_CONTEXT) );
|
|
|
|
pContext->pDeviceContext = pDeviceContext;
|
|
pContext->pNCB = pncb;
|
|
pContext->pzDnsName = pzDnsName;
|
|
pContext->pIpAddress = pIpAddress;
|
|
|
|
pContext->TransactId = htons(GetTransactId() + DIRECT_DNS_NAME_QUERY_BASE );
|
|
pContext->pchDomainName = NbtConfig.pDomainName;
|
|
pContext->Flags = DNS_DIRECT_DNS_SERVER;
|
|
|
|
for ( pch = &pzDnsName[0] ; *pch++ != '\0' ; )
|
|
{
|
|
if ( pch[0] == '.' )
|
|
{
|
|
pContext->Flags |= DNS_DIRECT_NAME_HAS_DOTS;
|
|
pContext->pchDomainName = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Put on the pending name queries list again so that when the query
|
|
// response comes in from DNS we can find the context.
|
|
//
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
|
|
InsertTailList(&NbtConfig.DNSDirectNameQueries,
|
|
&pContext->Linkage
|
|
);
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
status = UdpSendDNSBcastDirect( pContext,
|
|
(ULONG)pNbtGlobConfig->uRetryTimeout,
|
|
(ULONG)pNbtGlobConfig->uNumRetries
|
|
);
|
|
|
|
pncb->ncb_retcode = pncb->ncb_cmd_cplt = status ;
|
|
|
|
if ( status != NRC_PENDING )
|
|
{
|
|
pncb->ncb_retcode = pncb->ncb_cmd_cplt = status ;
|
|
|
|
DnsUnlinkAndCompleteDirect( pContext );
|
|
}
|
|
else
|
|
{
|
|
status = NRC_GOODRET;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
UdpSendDNSBcastDirect(
|
|
IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext,
|
|
IN ULONG Timeout,
|
|
IN ULONG Retries
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends a name query directed to the name server.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - success or not
|
|
|
|
History:
|
|
|
|
Adapted from UdpSendNSBcast() in "udpsend.c."
|
|
|
|
Earle R. Horton (earleh) March 18, 1996
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
tNAMEHDR *pNameHdr;
|
|
ULONG uLength;
|
|
ULONG uSentSize;
|
|
CTELockHandle OldIrq;
|
|
ULONG IpAddress;
|
|
tTIMERQENTRY *pTimerQEntry;
|
|
TDI_REQUEST TdiRequest;
|
|
PDNS_DIRECT_SEND_CONTEXT pSendContext;
|
|
|
|
pSendContext = CreateSendContextDirect(
|
|
pContext->pzDnsName,
|
|
pContext->pchDomainName,
|
|
(PVOID)&pNameHdr,
|
|
&uLength,
|
|
pContext);
|
|
|
|
if (pSendContext == NULL)
|
|
{
|
|
IF_DBG(NBT_DEBUG_NAMESRV)
|
|
KdPrint(("Nbt:Failed to Create Pdu to send to DNS.\n"));
|
|
return( NRC_NORES );
|
|
}
|
|
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
|
|
TdiRequest.Handle.AddressHandle = (PVOID)pContext->pDeviceContext->pNameServerFileObject;
|
|
|
|
// the completion routine is setup to free the pDgramTracker memory block
|
|
TdiRequest.RequestNotifyObject = SendDNSBcastDoneDirect;
|
|
TdiRequest.RequestContext = (PVOID)pSendContext;
|
|
|
|
// start the timer now...We didn't start it before because it could
|
|
// have expired during the dgram setup, perhaps before the Context was
|
|
// fully setup.
|
|
//
|
|
if (Timeout)
|
|
{
|
|
status = StartTimer(
|
|
Timeout,
|
|
pContext,
|
|
NULL,
|
|
DnsCompletionDirect,
|
|
NULL,
|
|
NULL,
|
|
(USHORT)Retries,
|
|
&pTimerQEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
// we need to differentiate the timer failing versus lack
|
|
// of resources
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
CTEMemFree(pSendContext);
|
|
|
|
return( NRC_NORES );
|
|
}
|
|
//
|
|
// Cross link the nameaddr and the timer so we can stop the timer
|
|
// when the name query response occurs
|
|
//
|
|
pTimerQEntry->pCacheEntry = pContext;
|
|
pContext->pTimer = pTimerQEntry;
|
|
}
|
|
|
|
//
|
|
// in the event that DHCP has just removed the IP address, just cancel
|
|
// the request
|
|
//
|
|
if (pContext->pDeviceContext->IpAddress == 0)
|
|
{
|
|
StopTimer ( pContext->pTimer, NULL, NULL );
|
|
pContext->Flags |= DNS_DIRECT_CANCELLED;
|
|
}
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
(VOID) TdiSendDatagram(
|
|
&TdiRequest,
|
|
&pSendContext->SendInfo,
|
|
uLength,
|
|
&uSentSize,
|
|
&pSendContext->SendBuffer,
|
|
NBT_NAME_SERVICE
|
|
);
|
|
|
|
return( NRC_PENDING );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
SendDNSBcastDoneDirect(
|
|
IN PVOID pSendContext,
|
|
IN NTSTATUS status,
|
|
IN ULONG lInfo
|
|
)
|
|
{
|
|
CTEMemFree(pSendContext);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
DoDnsCancelDirect(
|
|
PNCB pncb
|
|
)
|
|
{
|
|
PLIST_ENTRY pHead;
|
|
PLIST_ENTRY pEntry;
|
|
PDNS_DIRECT_WORK_ITEM_CONTEXT
|
|
pContext;
|
|
CTELockHandle OldIrq;
|
|
BOOL RetVal = FALSE;
|
|
|
|
pHead = pEntry = &NbtConfig.DNSDirectNameQueries;
|
|
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
|
|
while ((pEntry = pEntry->Flink) != pHead)
|
|
{
|
|
pContext = CONTAINING_RECORD(pEntry,DNS_DIRECT_WORK_ITEM_CONTEXT,Linkage);
|
|
if ( pContext->pNCB == pncb )
|
|
{
|
|
StopTimer ( pContext->pTimer, NULL, NULL );
|
|
pContext->Flags |= DNS_DIRECT_CANCELLED;
|
|
RetVal = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the timer code when the timer expires. It must
|
|
decide if another name query should be sent to the DNS server, and if not,
|
|
then it completes the request.
|
|
|
|
Arguments:
|
|
|
|
|
|
Notes:
|
|
--*/
|
|
VOID
|
|
DnsCompletionDirect(
|
|
PVOID pvContext,
|
|
PVOID pvContext2,
|
|
tTIMERQENTRY *pTimerQEntry
|
|
)
|
|
{
|
|
PDNS_DIRECT_WORK_ITEM_CONTEXT pContext;
|
|
tDEVICECONTEXT *pDeviceContext;
|
|
|
|
NTSTATUS status;
|
|
CTELockHandle OldIrq;
|
|
PCHAR pchDomainName;
|
|
USHORT Flags;
|
|
BOOL fOneMoreTry;
|
|
|
|
KdPrint(("DnsCompletion entered\r\n"));
|
|
|
|
pContext = (PDNS_DIRECT_WORK_ITEM_CONTEXT)pvContext;
|
|
|
|
|
|
// if the client completion routine is not set anymore, then the
|
|
// timer has been cancelled or completed and this routine should
|
|
// just clean up its buffers associated with the tracker (and return)
|
|
//
|
|
if (!pTimerQEntry)
|
|
{
|
|
// complete the request
|
|
LOCATION(0x52);
|
|
DnsUnlinkAndCompleteDirect( pContext );
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// to prevent a client from stopping the timer and deleting the
|
|
// pContext, grab the lock and check if the timer has been stopped
|
|
//
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq);
|
|
|
|
pDeviceContext = pContext->pDeviceContext;
|
|
|
|
if (pTimerQEntry->Flags & TIMER_RETIMED)
|
|
{
|
|
//
|
|
// Got a wait ACK from the server.
|
|
//
|
|
pTimerQEntry->Flags &= ~TIMER_RETIMED;
|
|
pTimerQEntry->Flags |= TIMER_RESTART;
|
|
//
|
|
// if we are not bound to this card than use a very short timeout
|
|
//
|
|
if (
|
|
(!pDeviceContext->pNameServerFileObject)
|
|
|| (pContext->Flags & DNS_DIRECT_CANCELLED)
|
|
)
|
|
{
|
|
pTimerQEntry->DeltaTime = 10;
|
|
}
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
return;
|
|
}
|
|
|
|
// If done with all the (3) retries with primary, try secondary DNS srvr
|
|
// If secondary not defined, or done with secondary as well, stop.
|
|
//
|
|
|
|
fOneMoreTry = TRUE;
|
|
|
|
if (!(--pTimerQEntry->Retries))
|
|
{
|
|
//
|
|
// if backup server is not defined, or if it is defined but we just
|
|
// finished trying backup server, go back and try primary server for
|
|
// "other domains"
|
|
// e.g. DNSDomains was defined as "msft.dom2.com,msft.dom3.com,msft.dom"
|
|
// We were pointing at msft.dom2.com. Now, we are done with that (and
|
|
// didn't get a response), so try msft.dom3.com
|
|
//
|
|
if ( ( !pDeviceContext->lDnsBackupServer ) ||
|
|
( pDeviceContext->lDnsBackupServer == LOOP_BACK ) ||
|
|
( pContext->Flags & DNS_DIRECT_DNS_BACKUP) )
|
|
{
|
|
//
|
|
// if we just got done trying primary domain name, try all the
|
|
// "other domains" specified
|
|
//
|
|
if (pContext->pchDomainName == NbtConfig.pDomainName)
|
|
{
|
|
pContext->pchDomainName = NbtConfig.pDNSDomains;
|
|
if ( pContext->pchDomainName )
|
|
{
|
|
pContext->Flags &= ~DNS_DIRECT_DNS_BACKUP;
|
|
pContext->Flags |= DNS_DIRECT_DNS_SERVER;
|
|
pTimerQEntry->Retries = NbtConfig.uNumRetries;
|
|
}
|
|
else
|
|
{
|
|
fOneMoreTry = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we had already started on "other domains", advance to the
|
|
// next domain within "other domains"
|
|
//
|
|
else if ( pContext->pchDomainName )
|
|
{
|
|
pchDomainName = pContext->pchDomainName;
|
|
while( *pchDomainName != ',' && // dom names separated by comma
|
|
*pchDomainName != ' ' && // or space
|
|
*pchDomainName != '\0' )
|
|
{
|
|
pchDomainName++;
|
|
}
|
|
|
|
if ( *pchDomainName == '\0' )
|
|
fOneMoreTry = FALSE;
|
|
else
|
|
{
|
|
pchDomainName++;
|
|
pContext->pchDomainName = pchDomainName;
|
|
pContext->Flags &= ~DNS_DIRECT_DNS_BACKUP;
|
|
pContext->Flags |= DNS_DIRECT_DNS_SERVER;
|
|
pTimerQEntry->Retries = NbtConfig.uNumRetries;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fOneMoreTry = FALSE;
|
|
}
|
|
}
|
|
|
|
// ok, prepare to try the backup server
|
|
else
|
|
{
|
|
pTimerQEntry->Retries = NbtConfig.uNumRetries;
|
|
|
|
pContext->Flags &= ~DNS_DIRECT_DNS_SERVER;
|
|
pContext->Flags |= DNS_DIRECT_DNS_BACKUP;
|
|
}
|
|
}
|
|
|
|
// we aren't done yet: send one more query and restart the timer
|
|
if (fOneMoreTry)
|
|
{
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
|
|
status = UdpSendDNSBcastDirect( pContext, 0, 0 );
|
|
|
|
pTimerQEntry->Flags |= TIMER_RESTART;
|
|
|
|
KdPrint(("One more DNS query sent out\r\n"));
|
|
}
|
|
|
|
// yup, all done: didn't find the name!
|
|
else
|
|
{
|
|
pTimerQEntry->Flags |= TIMER_RESTART;
|
|
StopTimer(pTimerQEntry,NULL,NULL);
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine "actually" completes the request, either by completing the
|
|
asociated NCB with some kind of failure, or passing it off to the
|
|
main NCB processing code.
|
|
|
|
Arguments:
|
|
|
|
|
|
Notes:
|
|
--*/
|
|
VOID
|
|
DnsActualCompletionDirect(
|
|
IN NBT_WORK_ITEM_CONTEXT * pnbtContext
|
|
)
|
|
{
|
|
PDNS_DIRECT_WORK_ITEM_CONTEXT pContext = pnbtContext->pClientContext;
|
|
uchar errNCB = NRC_GOODRET ;
|
|
NCB * pNCB = pContext->pNCB;
|
|
|
|
if ( pNCB->ncb_cmd_cplt == NRC_PENDING )
|
|
{
|
|
//
|
|
// Failed to resolve the name, or request was cancelled.
|
|
//
|
|
if ( pContext->pIpAddress[0] == 0 )
|
|
{
|
|
errNCB = NRC_CMDTMO;
|
|
}
|
|
else if ( pContext->Flags & DNS_DIRECT_CANCELLED )
|
|
{
|
|
errNCB = NRC_CMDCAN;
|
|
}
|
|
else
|
|
{
|
|
errNCB = VNBT_NCB_X ( pContext->pNCB, NULL, pContext->pIpAddress, NULL, 0 );
|
|
}
|
|
if ( errNCB != NRC_GOODRET )
|
|
{
|
|
pNCB->ncb_retcode = pNCB->ncb_cmd_cplt = errNCB ;
|
|
//
|
|
// call the post-routine only if the post-routine has been specified!
|
|
//
|
|
if ( pNCB->ncb_post )
|
|
{
|
|
typedef void (CALLBACK * VXDNCBPost )( void ) ;
|
|
VXDNCBPost ncbpost = (VXDNCBPost) pNCB->ncb_post ;
|
|
|
|
//
|
|
// Clients are expecting EBX to point to the NCB (instead of
|
|
// pushing it on the stack...). The post routine may trash
|
|
// ebp also, so save it.
|
|
//
|
|
_asm pushad ;
|
|
_asm mov ebx, pNCB ;
|
|
ncbpost() ;
|
|
_asm popad ;
|
|
}
|
|
}
|
|
}
|
|
|
|
CTEMemFree(pContext);
|
|
CTEMemFree(pnbtContext);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
DnsUnlinkAndCompleteDirect(
|
|
IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine unlinks and completes the request.
|
|
|
|
Arguments:
|
|
|
|
|
|
Notes:
|
|
--*/
|
|
{
|
|
RemoveEntryList(&pContext->Linkage);
|
|
|
|
VxdScheduleDelayedCall ( NULL,
|
|
pContext,
|
|
NULL,
|
|
DnsActualCompletionDirect,
|
|
pContext->pDeviceContext
|
|
);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
ProcessDnsResponseDirect(
|
|
IN tDEVICECONTEXT *pDeviceContext,
|
|
IN PVOID pSrcAddress,
|
|
IN tNAMEHDR UNALIGNED *pNameHdr,
|
|
IN LONG lNumBytes,
|
|
IN USHORT OpCodeFlags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the state of the name being resolved appropriately
|
|
depending on whether DNS sends a positive or a negative response to our
|
|
query; calls the client completion routine and stops any more DNS queries
|
|
from going.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS or STATUS_UNSUCCESSFUL
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
tDNS_QUERYRESP UNALIGNED *pQuery;
|
|
PLIST_ENTRY pHead;
|
|
PLIST_ENTRY pEntry;
|
|
PDNS_DIRECT_WORK_ITEM_CONTEXT
|
|
pContext;
|
|
COMPLETIONCLIENT pClientCompletion;
|
|
PVOID Context;
|
|
PTRANSPORT_ADDRESS pSourceAddress;
|
|
ULONG SrcAddress;
|
|
ULONG IpAddress;
|
|
tTIMERQENTRY *pTimer = NULL;
|
|
CTELockHandle OldIrq1;
|
|
LONG lNameSize;
|
|
LONG lTraversedSoFar=0;
|
|
CHAR pJunkBuf[NETBIOS_NAME_SIZE];
|
|
PUCHAR pchQry;
|
|
|
|
// make sure this is a response
|
|
|
|
if ( !(OpCodeFlags & OP_RESPONSE) )
|
|
{
|
|
CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: Bad OpCodeFlags\r\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
pSourceAddress = (PTRANSPORT_ADDRESS)pSrcAddress;
|
|
SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
|
|
|
|
CTESpinLock(&NbtConfig.JointLock,OldIrq1);
|
|
|
|
if ( ( pContext = FindContextDirect( pNameHdr->TransactId ) ) != NULL )
|
|
|
|
{
|
|
pContext->Flags |= DNS_DIRECT_ANSWERED;
|
|
if ( pTimer = pContext->pTimer )
|
|
{
|
|
//
|
|
// If the response we received doesn't resolve the name, we silently return,
|
|
// but make sure reties is set to 1 so that when timer fires again, we don't
|
|
// send another name query to the same server but instead timeout the
|
|
// attempt on this server
|
|
//
|
|
pTimer->Retries = 1;
|
|
}
|
|
//
|
|
// check the pdu size for errors
|
|
//
|
|
if (lNumBytes < DNS_MINIMUM_QUERYRESPONSE)
|
|
{
|
|
CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: Bad lNumBytes\r\n"));
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// BUGBUG: should we require authoritative responses from DNS servers?
|
|
//
|
|
|
|
//
|
|
// if it's a negative response, quit now!
|
|
//
|
|
if (IS_NEG_RESPONSE(OpCodeFlags))
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// if there is no answer section, return!
|
|
//
|
|
if ( !pNameHdr->AnCount )
|
|
{
|
|
CDbgPrint(DBGFLAG_ERROR,("ProcessDnsResponseDirect: No answer section\r\n"));
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// lNameSize is the length of the entire name, excluding the length byte
|
|
// for the first label (including length bytes of subsequent labels) and
|
|
// including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
|
|
//
|
|
DnsExtractName( (PCHAR)&pNameHdr->NameRR.NameLength,
|
|
lNumBytes,
|
|
pJunkBuf,
|
|
&lNameSize
|
|
);
|
|
pchQry = (PUCHAR)&pNameHdr->NameRR.NetBiosName[lNameSize];
|
|
|
|
lTraversedSoFar += lNameSize;
|
|
|
|
//
|
|
// if the Question section is returned with the response then we have
|
|
// a little more work to do! In this case, pQuery is pointing at the
|
|
// beginning of the QTYPE field (end of the QNAME)
|
|
//
|
|
if ( pNameHdr->QdCount )
|
|
{
|
|
pchQry += sizeof(tQUESTIONMODS);
|
|
lTraversedSoFar += sizeof(tQUESTIONMODS);
|
|
|
|
// most common case: 1st byte will be 0xC0, which means next byte points
|
|
// to the actual name. We don't care about the name, so we skip over
|
|
// both the bytes
|
|
//
|
|
if ( (*pchQry) == PTR_TO_NAME )
|
|
{
|
|
pchQry += sizeof(tDNS_LABEL);
|
|
lTraversedSoFar += sizeof(tDNS_LABEL);
|
|
}
|
|
|
|
//
|
|
// if some implementation doesn't optimize and copies the whole name
|
|
// again, skip over the length of the name
|
|
//
|
|
else
|
|
{
|
|
pchQry += (lNameSize+1); // +1 because of the 1st length byte!
|
|
lTraversedSoFar += (lNameSize+1);
|
|
}
|
|
}
|
|
|
|
pQuery = (tDNS_QUERYRESP *)pchQry;
|
|
|
|
//
|
|
// if this rr is telling us about canonical name, skip over it and go to
|
|
// where the ipaddr is
|
|
//
|
|
if (ntohs(pQuery->RrType) == DNS_CNAME)
|
|
{
|
|
//
|
|
// since this is CNAME, there is no ipaddr. Instead, the data is the
|
|
// canonical name whose length we are adding, and subtract ipaddr's len
|
|
//
|
|
pchQry += (sizeof(tDNS_QUERYRESP) - sizeof(ULONG));
|
|
pchQry += ntohs(pQuery->Length);
|
|
lTraversedSoFar += ntohs(pQuery->Length) + sizeof(tDNS_QUERYRESP) - sizeof(ULONG);
|
|
|
|
ASSERT(lNumBytes > lTraversedSoFar);
|
|
|
|
// most common case: 1st byte will be 0xC0, which means next byte points
|
|
// to the actual name. We don't care about the name, so we skip over
|
|
// both the bytes
|
|
//
|
|
if ( (*pchQry) == PTR_TO_NAME )
|
|
{
|
|
pchQry += sizeof(tDNS_LABEL);
|
|
lTraversedSoFar += sizeof(tDNS_LABEL);
|
|
}
|
|
|
|
//
|
|
// if some implementation doesn't optimize and copies the whole name
|
|
// again, skip over the length of the name
|
|
//
|
|
else
|
|
{
|
|
// we have already taken the name out. we are calling this routine
|
|
// just to see how big the canonical name is (i.e.lNameSize), to skip
|
|
// past it
|
|
//
|
|
DnsExtractName( pchQry,
|
|
lNumBytes-lTraversedSoFar,
|
|
pJunkBuf,
|
|
&lNameSize
|
|
);
|
|
|
|
//
|
|
// lNameSize is the length of the entire name, excluding the length byte
|
|
// for the first label (including length bytes of subsequent labels) and
|
|
// including the trailing 0 (tNAMEHDR struc takes care for 1st byte)
|
|
//
|
|
pchQry += lNameSize+1; // +1 for the length byte of first label
|
|
|
|
}
|
|
|
|
pQuery = (tDNS_QUERYRESP *)pchQry;
|
|
}
|
|
|
|
// if we came this far, it's a positive response. do the needful.
|
|
|
|
IpAddress = ntohl(pQuery->IpAddress);
|
|
|
|
if ( !NbtWouldLoopback( IpAddress ) )
|
|
{
|
|
pContext->pIpAddress[0] = IpAddress;
|
|
}
|
|
else
|
|
{
|
|
pContext->Flags |= DNS_DIRECT_CANCELLED;
|
|
}
|
|
|
|
//
|
|
// Set the backup name server to be the main name server
|
|
// if we got a response from it.
|
|
//
|
|
if ( SrcAddress == pContext->pDeviceContext->lDnsBackupServer )
|
|
{
|
|
pContext->pDeviceContext->lDnsBackupServer =
|
|
pContext->pDeviceContext->lDnsServerAddress;
|
|
|
|
pContext->pDeviceContext->lDnsServerAddress = SrcAddress;
|
|
}
|
|
|
|
StopTimer(pTimer,NULL,NULL);
|
|
}
|
|
|
|
done:
|
|
|
|
CTESpinFree(&NbtConfig.JointLock,OldIrq1);
|
|
return;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
PDNS_DIRECT_SEND_CONTEXT
|
|
CreateSendContextDirect(
|
|
IN PCHAR pName,
|
|
IN PCHAR pchDomainName,
|
|
OUT PVOID *pHdrs,
|
|
OUT PULONG pLength,
|
|
IN PDNS_DIRECT_WORK_ITEM_CONTEXT pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds a name query pdu
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
PDNS_DIRECT_SEND_CONTEXT - a pointer to a data structure used for the datagram
|
|
send that must be freed by the datagram send completion routine
|
|
|
|
--*/
|
|
{
|
|
tNAMEHDR *pNameHdr;
|
|
ULONG uLength;
|
|
ULONG uDomainNameSize;
|
|
tGENERALRR *pGeneral;
|
|
CTELockHandle OldIrq;
|
|
PDNS_DIRECT_SEND_CONTEXT
|
|
pSendContext;
|
|
|
|
uDomainNameSize = domnamelen(pchDomainName) + 1; // +1 for len byte
|
|
if (uDomainNameSize > 1)
|
|
{
|
|
uDomainNameSize++; // for the null byte
|
|
}
|
|
|
|
// size is size of the namehdr structure -1 for the NetbiosName[1]
|
|
// + the 32 bytes for the half ascii name +
|
|
// scope + size of the General RR structure
|
|
uLength = sizeof(DNS_DIRECT_SEND_CONTEXT) - 1
|
|
+ uDomainNameSize
|
|
+ sizeof(ULONG)
|
|
+ strlen(pName)
|
|
+ 1;
|
|
|
|
// Note that this memory must be deallocated when the send completes in
|
|
// SendDNSBcastDoneDirect()
|
|
pSendContext = NbtAllocMem((USHORT)uLength ,NBT_TAG('X'));
|
|
|
|
if (pSendContext)
|
|
{
|
|
CTEZeroMemory((PVOID)pSendContext,uLength);
|
|
|
|
pNameHdr = &pSendContext->NameHdr;
|
|
|
|
pNameHdr->TransactId = pContext->TransactId;
|
|
pNameHdr->QdCount = 1;
|
|
pNameHdr->AnCount = 0;
|
|
pNameHdr->NsCount = 0;
|
|
|
|
*pHdrs = (PVOID)pNameHdr;
|
|
*pLength = uLength = uLength - ( sizeof(DNS_DIRECT_SEND_CONTEXT) - sizeof(tNAMEHDR) );
|
|
|
|
// copy the netbios name ... adding the scope too
|
|
if ( pContext->Flags & DNS_DIRECT_NAME_HAS_DOTS )
|
|
{
|
|
char * p;
|
|
for ( p = pName ; *p != '.' ; p++ );
|
|
p[0] = '\0';
|
|
pGeneral = (tGENERALRR *)DnsStoreName(
|
|
(PCHAR)&pNameHdr->NameRR.NameLength,
|
|
pName,
|
|
&p[1],
|
|
eDIRECT_DNS_NAME_QUERY);
|
|
p[0] = '.';
|
|
}
|
|
else
|
|
{
|
|
pGeneral = (tGENERALRR *)DnsStoreName(
|
|
(PCHAR)&pNameHdr->NameRR.NameLength,
|
|
pName,
|
|
pContext->pchDomainName,
|
|
eDIRECT_DNS_NAME_QUERY);
|
|
}
|
|
|
|
|
|
pGeneral->Question.QuestionTypeClass = htonl(QUEST_DNSINTERNET);
|
|
|
|
pNameHdr->OpCodeFlags = (FL_RECURDESIRE);
|
|
|
|
pNameHdr->ArCount = 0;
|
|
|
|
pSendContext->SendBuffer.pDgramHdr = pNameHdr;
|
|
pSendContext->SendBuffer.HdrLength = uLength;
|
|
pSendContext->SendBuffer.pBuffer = NULL;
|
|
pSendContext->SendBuffer.Length = 0;
|
|
pSendContext->SendInfo.RemoteAddressLength = sizeof(pSendContext->NameServerAddress);
|
|
pSendContext->SendInfo.RemoteAddress = (PTRANSPORT_ADDRESS)&pSendContext->NameServerAddress;
|
|
pSendContext->NameServerAddress.TAAddressCount = 1;
|
|
pSendContext->NameServerAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
|
|
pSendContext->NameServerAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
|
pSendContext->NameServerAddress.Address[0].Address[0].sin_port = htons(NbtConfig.DnsServerPort);
|
|
if ( pContext->Flags & DNS_DIRECT_DNS_SERVER )
|
|
{
|
|
pSendContext->NameServerAddress.Address[0].Address[0].in_addr = htonl(pContext->pDeviceContext->lDnsServerAddress);
|
|
}
|
|
else
|
|
{
|
|
pSendContext->NameServerAddress.Address[0].Address[0].in_addr = htonl(pContext->pDeviceContext->lDnsBackupServer);
|
|
}
|
|
}
|
|
|
|
return(pSendContext);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
PDNS_DIRECT_WORK_ITEM_CONTEXT
|
|
FindContextDirect(
|
|
USHORT TransactionId
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine find the DNS_DIRECT_WORK_ITEM_CONTEXT having the given
|
|
TransactId
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
PDNS_DIRECT_SEND_CONTEXT - a pointer to the pContext having the given
|
|
TransactId, or NULL
|
|
|
|
Notes:
|
|
|
|
Called with NbtConfig.JointLock held
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY pHead;
|
|
PLIST_ENTRY pEntry;
|
|
PDNS_DIRECT_WORK_ITEM_CONTEXT
|
|
pContext;
|
|
|
|
pHead = pEntry = &NbtConfig.DNSDirectNameQueries;
|
|
|
|
while ((pEntry = pEntry->Flink) != pHead)
|
|
{
|
|
pContext = CONTAINING_RECORD(pEntry,DNS_DIRECT_WORK_ITEM_CONTEXT,Linkage);
|
|
if ( pContext->TransactId == TransactionId )
|
|
{
|
|
return pContext;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
IpToAscii(
|
|
IN DWORD IpAddress,
|
|
IN OUT PCHAR pcAscii
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts an IP address to a NetBIOS name.
|
|
|
|
Arguments:
|
|
|
|
DWORD IP address
|
|
PCHAR String pointer allocated for 16 bytes
|
|
|
|
Return Value:
|
|
|
|
Note
|
|
|
|
Notes:
|
|
|
|
This is a gigantic hack designed to get "net use \\<dnsname>"
|
|
working under Windows 95 OPK2 without destabilizing the existing
|
|
code base over much.
|
|
|
|
--*/
|
|
{
|
|
PCHAR pcIpAddressBytes = ( (PCHAR) &IpAddress ) + 3;
|
|
PCHAR pcIp = pcAscii;
|
|
|
|
int i,j,k,l,m;
|
|
|
|
memset ( pcAscii, 0x20, NETBIOS_NAME_SIZE );
|
|
|
|
for ( i = 4 ; i-- > 0 ; )
|
|
{
|
|
|
|
j = *pcIpAddressBytes-- & 0x000000FF;
|
|
k = j/100;
|
|
l = (j%100)/10;
|
|
m = j%10;
|
|
|
|
if ( k )
|
|
{
|
|
*pcIp++ = k + '0';
|
|
*pcIp++ = l + '0';
|
|
}
|
|
|
|
else if ( l )
|
|
{
|
|
*pcIp++ = l + '0';
|
|
}
|
|
|
|
*pcIp++ = m + '0';
|
|
|
|
if ( i )
|
|
{
|
|
*pcIp++ = '.';
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|