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
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
|