Leaked source code of windows server 2003
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.
 
 
 
 
 
 

636 lines
18 KiB

/*++
Copyright (c) 1997-2002 Microsoft Corporation
Module Name:
DnsPluginSample.c
Abstract:
Domain Name System (DNS) Sample Plugin DLL
Author:
Jeff Westhead jwesth January 2002
Revision History:
--*/
// -------------------------------------------------------------------------
// Documentation
// -------------------------------------------------------------------------
/*
Installing the plugin DLL
---------------------------
- copy plugin to any directory, for example c:\bin
- configure DNS server to load plugin by running this command:
dnscmd /Config /ServerLevelPluginDll c:\bin\dnssampleplugin.dll
- restart the DNS service
net stop dns & net start dns
Uninstalling the plugin DLL
-----------------------------
- configure DNS server to stop loading the plugin by running this command:
dnscmd /Config /ServerLevelPluginDll
- restart the DNS service
net stop dns & net start dns
Querying current plugin DLL
-----------------------------
- run this command to see the current plugin DLL name
dnscmd /Info /ServerLevelPluginDll
*/
// -------------------------------------------------------------------------
// Include directives
// -------------------------------------------------------------------------
#include "DnsPluginSample.h"
// -------------------------------------------------------------------------
// Macros
// -------------------------------------------------------------------------
#define SIZEOF_DB_NAME( pDbName ) ( ( pDbName )->Length + sizeof( UCHAR ) * 2 )
// -------------------------------------------------------------------------
// Global variables
// -------------------------------------------------------------------------
PLUGIN_ALLOCATOR_FUNCTION g_pDnsAllocate = NULL;
PLUGIN_FREE_FUNCTION g_pDnsFree = NULL;
// -------------------------------------------------------------------------
// Functions
// -------------------------------------------------------------------------
/*++
Routine Description:
DllMain
Arguments:
Return Value:
--*/
BOOL WINAPI
DllMain(
HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved
)
{
return TRUE;
} // DllMain
/*++
Routine Description:
DnsPluginInitialize is called by the DNS server to initialize
the plugin.
Arguments:
pDnsAllocator -- allocator function for future allocation of DNS records
Return Value:
Return ERROR_SUCCESS or error code if initialization failed.
--*/
DWORD
DnsPluginInitialize(
PLUGIN_ALLOCATOR_FUNCTION pDnsAllocateFunction,
PLUGIN_FREE_FUNCTION pDnsFreeFunction
)
{
WSADATA wsaData;
g_pDnsAllocate = pDnsAllocateFunction;
g_pDnsFree = pDnsFreeFunction;
WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
return ERROR_SUCCESS;
} // DnsPluginInitialize
/*++
Routine Description:
DnsPluginCleanup is called by the DNS server to terminate hooked lookups.
The plugin must close all connections and free all resources.
Arguments:
None.
Return Value:
Return ERROR_SUCCESS or error code if cleanup failed.
--*/
DWORD
DnsPluginCleanup(
VOID
)
{
g_pDnsAllocate = NULL;
g_pDnsFree = NULL;
WSACleanup();
return ERROR_SUCCESS;
} // DnsPluginCleanup
/*++
Routine Description:
This function returns a DNS name in dotted string format as a DB_NAME.
Arguments:
pszDottedName -- DNS name to be converted into DB_NAME format
pDbName -- pointer to structure where DB_NAME value will be written
Return Value:
Return ERROR_SUCCESS or error code on failure.
--*/
DWORD
convertDottedNameToDbName(
PSTR pszDottedName,
DB_NAME * pDbName )
{
DWORD status = ERROR_SUCCESS;
PSTR psz;
PSTR pszCharDest = &pDbName->RawName[ 1 ];
PUCHAR puchLabelLength = &pDbName->RawName[ 0 ];
memset( pDbName, 0, sizeof( *pDbName ) );
if ( !pszDottedName )
{
goto Done;
}
//
// Account for first length byte in the name.
//
pDbName->Length = 1;
//
// Loop through characters of the dotted name, converting to DB_NAME.
//
for ( psz = pszDottedName; *psz; ++psz )
{
if ( *psz == '.' )
{
if ( *( psz + 1 ) == '\0' )
{
break; // Terminating dot - ignore.
}
puchLabelLength = pszCharDest++;
++pDbName->Length;
++pDbName->LabelCount;
}
else
{
++pDbName->Length;
++*puchLabelLength;
*pszCharDest++ = *psz;
}
}
//
// Account for terminating zero character.
//
++pDbName->LabelCount;
++pDbName->Length;
Done:
return status;
} // convertDottedNameToDbName
/*++
Routine Description:
DnsPluginQuery is called by the DNS server to retrieve a list of
DNS records for a DNS name. The plugin must fabricate a linked list of
DNS records if the name is valid.
Arguments:
pszQueryName -- DNS name that is being queried for, note this will always
be a fully-qualified domain name and will always end in a period
wQueryType -- record type desired by the DNS server
pszRecordOwnerName -- static buffer in the DNS server where the plugin
may write the owner name of the record list if it does not match the
query name -- currently this should only be used when returning a
single SOA record for NAME_ERROR and NO_RECORDS responses
ppDnsRecordListHead -- pointer to first element of linked list of DNS
records; this list is fabricated by the plugin and returned on output
Return Value:
Return ERROR_SUCCESS or error code if cleanup failed.
--*/
DWORD
DnsPluginQuery(
PSTR pszQueryName,
WORD wQueryType,
PSTR pszRecordOwnerName,
PDB_RECORD * ppDnsRecordListHead
)
{
DWORD status = DNS_PLUGIN_SUCCESS;
PDB_RECORD prr;
PDB_RECORD prrlast = NULL;
ASSERT( ppDnsRecordListHead != NULL );
*ppDnsRecordListHead = NULL;
//
// This macro performs allocation error checking and automates the
// linking of new DNS resource records as they are allocated.
//
#define CheckNewRRPointer( pNewRR ) \
if ( pNewRR == NULL ) { status = DNS_PLUGIN_OUT_OF_MEMORY; goto Done; } \
if ( *ppDnsRecordListHead == NULL ) { *ppDnsRecordListHead = pNewRR; } \
if ( prrlast ) { prrlast->pRRNext = pNewRR; } \
prrlast = pNewRR
//
// This plugin sythesizes a DNS zone called "dnssample.com". If the
// query is for a name outside that zone the plugin will return name error.
//
#define PLUGIN_ZONE_NAME "dnssample.com."
if ( strlen( pszQueryName ) < strlen( PLUGIN_ZONE_NAME ) ||
_stricmp(
pszQueryName + strlen( pszQueryName ) - strlen( PLUGIN_ZONE_NAME ),
PLUGIN_ZONE_NAME ) != 0 )
{
status = DNS_PLUGIN_NAME_OUT_OF_SCOPE;
goto Done;
}
//
// Parse the query name to determine what records should be returned.
//
if ( strlen( pszQueryName ) == strlen( PLUGIN_ZONE_NAME ) )
{
switch ( wQueryType )
{
case DNS_TYPE_SOA:
{
// At the zone root return 2 arbitrary NS records.
DB_NAME dbnamePrimaryServer;
DB_NAME dbnameZoneAdmin;
status = convertDottedNameToDbName(
"ns1." PLUGIN_ZONE_NAME,
&dbnamePrimaryServer ) ;
if ( status != ERROR_SUCCESS )
{
break;
}
status = convertDottedNameToDbName(
"admin." PLUGIN_ZONE_NAME,
&dbnameZoneAdmin ) ;
if ( status != ERROR_SUCCESS )
{
break;
}
prr = g_pDnsAllocate(
sizeof( DWORD ) * 5 +
SIZEOF_DB_NAME( &dbnamePrimaryServer ) +
SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_SOA;
prr->Data.SOA.dwSerialNo = htonl( 1000 );
prr->Data.SOA.dwRefresh = htonl( 3600 );
prr->Data.SOA.dwRetry = htonl( 600 );
prr->Data.SOA.dwExpire = htonl( 1800 );
prr->Data.SOA.dwMinimumTtl = htonl( 60 );
memcpy(
&prr->Data.SOA.namePrimaryServer,
&dbnamePrimaryServer,
SIZEOF_DB_NAME( &dbnamePrimaryServer ) );
memcpy(
( PBYTE ) &prr->Data.SOA.namePrimaryServer +
SIZEOF_DB_NAME( &dbnamePrimaryServer ),
&dbnameZoneAdmin,
SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
break;
}
case DNS_TYPE_NS:
{
// At the zone root return 2 arbitrary NS records.
DB_NAME dbname;
status = convertDottedNameToDbName(
"ns1." PLUGIN_ZONE_NAME,
&dbname );
if ( status != ERROR_SUCCESS )
{
break;
}
prr = g_pDnsAllocate( SIZEOF_DB_NAME( &dbname ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_NS;
memcpy(
&prr->Data.PTR.nameTarget,
&dbname,
SIZEOF_DB_NAME( &dbname ) );
status = convertDottedNameToDbName(
"ns2." PLUGIN_ZONE_NAME,
&dbname ) ;
if ( status != ERROR_SUCCESS )
{
break;
}
prr = g_pDnsAllocate( SIZEOF_DB_NAME( &dbname ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_NS;
memcpy(
&prr->Data.PTR.nameTarget,
&dbname,
SIZEOF_DB_NAME( &dbname ) );
break;
}
case DNS_TYPE_MX:
{
// At the zone root return 2 arbitrary MX records.
DB_NAME dbname;
status = convertDottedNameToDbName(
"mail1." PLUGIN_ZONE_NAME,
&dbname ) ;
if ( status != ERROR_SUCCESS )
{
break;
}
prr = g_pDnsAllocate(
sizeof( WORD ) + SIZEOF_DB_NAME( &dbname ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_MX;
prr->Data.MX.wPreference = htons( 10 );
memcpy(
&prr->Data.MX.nameExchange,
&dbname,
SIZEOF_DB_NAME( &dbname ) );
status = convertDottedNameToDbName(
"mail2." PLUGIN_ZONE_NAME,
&dbname ) ;
if ( status != ERROR_SUCCESS )
{
break;
}
prr = g_pDnsAllocate(
sizeof( WORD ) + SIZEOF_DB_NAME( &dbname ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_MX;
prr->Data.MX.wPreference = htons( 20 );
memcpy(
&prr->Data.MX.nameExchange,
&dbname,
SIZEOF_DB_NAME( &dbname ) );
break;
}
case DNS_TYPE_A:
// At the zone root return 3 arbitrary A records.
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "1.1.1.1" );
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "2.2.2.2" );
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "3.3.3.3" );
break;
default:
status = DNS_PLUGIN_NO_RECORDS;
break;
}
}
else if ( _stricmp( pszQueryName, "www." PLUGIN_ZONE_NAME ) == 0 ||
_stricmp( pszQueryName, "mail1." PLUGIN_ZONE_NAME ) == 0 ||
_stricmp( pszQueryName, "mail2." PLUGIN_ZONE_NAME ) == 0 )
{
if ( wQueryType == DNS_TYPE_A )
{
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "100.100.100.1" );
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "100.100.100.2" );
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "100.100.100.3" );
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "100.100.100.4" );
}
else
{
status = DNS_PLUGIN_NO_RECORDS;
}
}
else if ( _stricmp( pszQueryName, "ns1." PLUGIN_ZONE_NAME ) == 0 )
{
if ( wQueryType == DNS_TYPE_A )
{
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "100.100.100.50" );
}
else
{
status = DNS_PLUGIN_NO_RECORDS;
}
}
else if ( _stricmp( pszQueryName, "ns2." PLUGIN_ZONE_NAME ) == 0 )
{
if ( wQueryType == DNS_TYPE_A )
{
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "100.100.100.51" );
}
else
{
status = DNS_PLUGIN_NO_RECORDS;
}
}
else if ( strstr( pszQueryName, "aaa" ) )
{
//
// For any other queried name in the zone that contains "aaa",
// return an arbitrary A record. Note: using strstr here is
// a bad idea. All string comparisons should be case insensitive.
//
if ( wQueryType == DNS_TYPE_A )
{
prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_A;
prr->Data.A.ipAddress = inet_addr( "1.2.3.4" );
prr->dwTtlSeconds = 1200;
}
else
{
status = DNS_PLUGIN_NO_RECORDS;
}
}
else
{
status = DNS_PLUGIN_NAME_ERROR;
}
Done:
if ( status == DNS_PLUGIN_NO_RECORDS || status == DNS_PLUGIN_NAME_ERROR )
{
//
// Return the zone SOA.
//
DB_NAME dbnamePrimaryServer;
DB_NAME dbnameZoneAdmin;
if ( convertDottedNameToDbName(
"ns1." PLUGIN_ZONE_NAME,
&dbnamePrimaryServer ) != ERROR_SUCCESS )
{
goto Return;
}
if ( convertDottedNameToDbName(
"admin." PLUGIN_ZONE_NAME,
&dbnameZoneAdmin ) != ERROR_SUCCESS )
{
goto Return;
}
prr = g_pDnsAllocate(
sizeof( DWORD ) * 5 +
SIZEOF_DB_NAME( &dbnamePrimaryServer ) +
SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
CheckNewRRPointer( prr );
prr->wType = DNS_TYPE_SOA;
prr->Data.SOA.dwSerialNo = htonl( 1000 );
prr->Data.SOA.dwRefresh = htonl( 3600 );
prr->Data.SOA.dwRetry = htonl( 600 );
prr->Data.SOA.dwExpire = htonl( 1800 );
prr->Data.SOA.dwMinimumTtl = htonl( 60 );
memcpy(
&prr->Data.SOA.namePrimaryServer,
&dbnamePrimaryServer,
SIZEOF_DB_NAME( &dbnamePrimaryServer ) );
memcpy(
( PBYTE ) &prr->Data.SOA.namePrimaryServer +
SIZEOF_DB_NAME( &dbnamePrimaryServer ),
&dbnameZoneAdmin,
SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
//
// Set owner name for the SOA.
//
if ( pszRecordOwnerName )
{
strcpy( pszRecordOwnerName, PLUGIN_ZONE_NAME );
}
}
else if ( status != ERROR_SUCCESS )
{
PDB_RECORD prrnext;
//
// On failure free any records allocated.
//
for ( prr = *ppDnsRecordListHead; prr; prr = prrnext )
{
prrnext = prr->pRRNext;
g_pDnsFree( prr );
}
*ppDnsRecordListHead = NULL;
}
Return:
return status;
} // DnsPluginQuery