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

  1. /*++
  2. Copyright (c) 1997-2002 Microsoft Corporation
  3. Module Name:
  4. DnsPluginSample.c
  5. Abstract:
  6. Domain Name System (DNS) Sample Plugin DLL
  7. Author:
  8. Jeff Westhead jwesth January 2002
  9. Revision History:
  10. --*/
  11. // -------------------------------------------------------------------------
  12. // Documentation
  13. // -------------------------------------------------------------------------
  14. /*
  15. Installing the plugin DLL
  16. ---------------------------
  17. - copy plugin to any directory, for example c:\bin
  18. - configure DNS server to load plugin by running this command:
  19. dnscmd /Config /ServerLevelPluginDll c:\bin\dnssampleplugin.dll
  20. - restart the DNS service
  21. net stop dns & net start dns
  22. Uninstalling the plugin DLL
  23. -----------------------------
  24. - configure DNS server to stop loading the plugin by running this command:
  25. dnscmd /Config /ServerLevelPluginDll
  26. - restart the DNS service
  27. net stop dns & net start dns
  28. Querying current plugin DLL
  29. -----------------------------
  30. - run this command to see the current plugin DLL name
  31. dnscmd /Info /ServerLevelPluginDll
  32. */
  33. // -------------------------------------------------------------------------
  34. // Include directives
  35. // -------------------------------------------------------------------------
  36. #include "DnsPluginSample.h"
  37. // -------------------------------------------------------------------------
  38. // Macros
  39. // -------------------------------------------------------------------------
  40. #define SIZEOF_DB_NAME( pDbName ) ( ( pDbName )->Length + sizeof( UCHAR ) * 2 )
  41. // -------------------------------------------------------------------------
  42. // Global variables
  43. // -------------------------------------------------------------------------
  44. PLUGIN_ALLOCATOR_FUNCTION g_pDnsAllocate = NULL;
  45. PLUGIN_FREE_FUNCTION g_pDnsFree = NULL;
  46. // -------------------------------------------------------------------------
  47. // Functions
  48. // -------------------------------------------------------------------------
  49. /*++
  50. Routine Description:
  51. DllMain
  52. Arguments:
  53. Return Value:
  54. --*/
  55. BOOL WINAPI
  56. DllMain(
  57. HANDLE hModule,
  58. DWORD dwReason,
  59. LPVOID lpReserved
  60. )
  61. {
  62. return TRUE;
  63. } // DllMain
  64. /*++
  65. Routine Description:
  66. DnsPluginInitialize is called by the DNS server to initialize
  67. the plugin.
  68. Arguments:
  69. pDnsAllocator -- allocator function for future allocation of DNS records
  70. Return Value:
  71. Return ERROR_SUCCESS or error code if initialization failed.
  72. --*/
  73. DWORD
  74. DnsPluginInitialize(
  75. PLUGIN_ALLOCATOR_FUNCTION pDnsAllocateFunction,
  76. PLUGIN_FREE_FUNCTION pDnsFreeFunction
  77. )
  78. {
  79. WSADATA wsaData;
  80. g_pDnsAllocate = pDnsAllocateFunction;
  81. g_pDnsFree = pDnsFreeFunction;
  82. WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
  83. return ERROR_SUCCESS;
  84. } // DnsPluginInitialize
  85. /*++
  86. Routine Description:
  87. DnsPluginCleanup is called by the DNS server to terminate hooked lookups.
  88. The plugin must close all connections and free all resources.
  89. Arguments:
  90. None.
  91. Return Value:
  92. Return ERROR_SUCCESS or error code if cleanup failed.
  93. --*/
  94. DWORD
  95. DnsPluginCleanup(
  96. VOID
  97. )
  98. {
  99. g_pDnsAllocate = NULL;
  100. g_pDnsFree = NULL;
  101. WSACleanup();
  102. return ERROR_SUCCESS;
  103. } // DnsPluginCleanup
  104. /*++
  105. Routine Description:
  106. This function returns a DNS name in dotted string format as a DB_NAME.
  107. Arguments:
  108. pszDottedName -- DNS name to be converted into DB_NAME format
  109. pDbName -- pointer to structure where DB_NAME value will be written
  110. Return Value:
  111. Return ERROR_SUCCESS or error code on failure.
  112. --*/
  113. DWORD
  114. convertDottedNameToDbName(
  115. PSTR pszDottedName,
  116. DB_NAME * pDbName )
  117. {
  118. DWORD status = ERROR_SUCCESS;
  119. PSTR psz;
  120. PSTR pszCharDest = &pDbName->RawName[ 1 ];
  121. PUCHAR puchLabelLength = &pDbName->RawName[ 0 ];
  122. memset( pDbName, 0, sizeof( *pDbName ) );
  123. if ( !pszDottedName )
  124. {
  125. goto Done;
  126. }
  127. //
  128. // Account for first length byte in the name.
  129. //
  130. pDbName->Length = 1;
  131. //
  132. // Loop through characters of the dotted name, converting to DB_NAME.
  133. //
  134. for ( psz = pszDottedName; *psz; ++psz )
  135. {
  136. if ( *psz == '.' )
  137. {
  138. if ( *( psz + 1 ) == '\0' )
  139. {
  140. break; // Terminating dot - ignore.
  141. }
  142. puchLabelLength = pszCharDest++;
  143. ++pDbName->Length;
  144. ++pDbName->LabelCount;
  145. }
  146. else
  147. {
  148. ++pDbName->Length;
  149. ++*puchLabelLength;
  150. *pszCharDest++ = *psz;
  151. }
  152. }
  153. //
  154. // Account for terminating zero character.
  155. //
  156. ++pDbName->LabelCount;
  157. ++pDbName->Length;
  158. Done:
  159. return status;
  160. } // convertDottedNameToDbName
  161. /*++
  162. Routine Description:
  163. DnsPluginQuery is called by the DNS server to retrieve a list of
  164. DNS records for a DNS name. The plugin must fabricate a linked list of
  165. DNS records if the name is valid.
  166. Arguments:
  167. pszQueryName -- DNS name that is being queried for, note this will always
  168. be a fully-qualified domain name and will always end in a period
  169. wQueryType -- record type desired by the DNS server
  170. pszRecordOwnerName -- static buffer in the DNS server where the plugin
  171. may write the owner name of the record list if it does not match the
  172. query name -- currently this should only be used when returning a
  173. single SOA record for NAME_ERROR and NO_RECORDS responses
  174. ppDnsRecordListHead -- pointer to first element of linked list of DNS
  175. records; this list is fabricated by the plugin and returned on output
  176. Return Value:
  177. Return ERROR_SUCCESS or error code if cleanup failed.
  178. --*/
  179. DWORD
  180. DnsPluginQuery(
  181. PSTR pszQueryName,
  182. WORD wQueryType,
  183. PSTR pszRecordOwnerName,
  184. PDB_RECORD * ppDnsRecordListHead
  185. )
  186. {
  187. DWORD status = DNS_PLUGIN_SUCCESS;
  188. PDB_RECORD prr;
  189. PDB_RECORD prrlast = NULL;
  190. ASSERT( ppDnsRecordListHead != NULL );
  191. *ppDnsRecordListHead = NULL;
  192. //
  193. // This macro performs allocation error checking and automates the
  194. // linking of new DNS resource records as they are allocated.
  195. //
  196. #define CheckNewRRPointer( pNewRR ) \
  197. if ( pNewRR == NULL ) { status = DNS_PLUGIN_OUT_OF_MEMORY; goto Done; } \
  198. if ( *ppDnsRecordListHead == NULL ) { *ppDnsRecordListHead = pNewRR; } \
  199. if ( prrlast ) { prrlast->pRRNext = pNewRR; } \
  200. prrlast = pNewRR
  201. //
  202. // This plugin sythesizes a DNS zone called "dnssample.com". If the
  203. // query is for a name outside that zone the plugin will return name error.
  204. //
  205. #define PLUGIN_ZONE_NAME "dnssample.com."
  206. if ( strlen( pszQueryName ) < strlen( PLUGIN_ZONE_NAME ) ||
  207. _stricmp(
  208. pszQueryName + strlen( pszQueryName ) - strlen( PLUGIN_ZONE_NAME ),
  209. PLUGIN_ZONE_NAME ) != 0 )
  210. {
  211. status = DNS_PLUGIN_NAME_OUT_OF_SCOPE;
  212. goto Done;
  213. }
  214. //
  215. // Parse the query name to determine what records should be returned.
  216. //
  217. if ( strlen( pszQueryName ) == strlen( PLUGIN_ZONE_NAME ) )
  218. {
  219. switch ( wQueryType )
  220. {
  221. case DNS_TYPE_SOA:
  222. {
  223. // At the zone root return 2 arbitrary NS records.
  224. DB_NAME dbnamePrimaryServer;
  225. DB_NAME dbnameZoneAdmin;
  226. status = convertDottedNameToDbName(
  227. "ns1." PLUGIN_ZONE_NAME,
  228. &dbnamePrimaryServer ) ;
  229. if ( status != ERROR_SUCCESS )
  230. {
  231. break;
  232. }
  233. status = convertDottedNameToDbName(
  234. "admin." PLUGIN_ZONE_NAME,
  235. &dbnameZoneAdmin ) ;
  236. if ( status != ERROR_SUCCESS )
  237. {
  238. break;
  239. }
  240. prr = g_pDnsAllocate(
  241. sizeof( DWORD ) * 5 +
  242. SIZEOF_DB_NAME( &dbnamePrimaryServer ) +
  243. SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
  244. CheckNewRRPointer( prr );
  245. prr->wType = DNS_TYPE_SOA;
  246. prr->Data.SOA.dwSerialNo = htonl( 1000 );
  247. prr->Data.SOA.dwRefresh = htonl( 3600 );
  248. prr->Data.SOA.dwRetry = htonl( 600 );
  249. prr->Data.SOA.dwExpire = htonl( 1800 );
  250. prr->Data.SOA.dwMinimumTtl = htonl( 60 );
  251. memcpy(
  252. &prr->Data.SOA.namePrimaryServer,
  253. &dbnamePrimaryServer,
  254. SIZEOF_DB_NAME( &dbnamePrimaryServer ) );
  255. memcpy(
  256. ( PBYTE ) &prr->Data.SOA.namePrimaryServer +
  257. SIZEOF_DB_NAME( &dbnamePrimaryServer ),
  258. &dbnameZoneAdmin,
  259. SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
  260. break;
  261. }
  262. case DNS_TYPE_NS:
  263. {
  264. // At the zone root return 2 arbitrary NS records.
  265. DB_NAME dbname;
  266. status = convertDottedNameToDbName(
  267. "ns1." PLUGIN_ZONE_NAME,
  268. &dbname );
  269. if ( status != ERROR_SUCCESS )
  270. {
  271. break;
  272. }
  273. prr = g_pDnsAllocate( SIZEOF_DB_NAME( &dbname ) );
  274. CheckNewRRPointer( prr );
  275. prr->wType = DNS_TYPE_NS;
  276. memcpy(
  277. &prr->Data.PTR.nameTarget,
  278. &dbname,
  279. SIZEOF_DB_NAME( &dbname ) );
  280. status = convertDottedNameToDbName(
  281. "ns2." PLUGIN_ZONE_NAME,
  282. &dbname ) ;
  283. if ( status != ERROR_SUCCESS )
  284. {
  285. break;
  286. }
  287. prr = g_pDnsAllocate( SIZEOF_DB_NAME( &dbname ) );
  288. CheckNewRRPointer( prr );
  289. prr->wType = DNS_TYPE_NS;
  290. memcpy(
  291. &prr->Data.PTR.nameTarget,
  292. &dbname,
  293. SIZEOF_DB_NAME( &dbname ) );
  294. break;
  295. }
  296. case DNS_TYPE_MX:
  297. {
  298. // At the zone root return 2 arbitrary MX records.
  299. DB_NAME dbname;
  300. status = convertDottedNameToDbName(
  301. "mail1." PLUGIN_ZONE_NAME,
  302. &dbname ) ;
  303. if ( status != ERROR_SUCCESS )
  304. {
  305. break;
  306. }
  307. prr = g_pDnsAllocate(
  308. sizeof( WORD ) + SIZEOF_DB_NAME( &dbname ) );
  309. CheckNewRRPointer( prr );
  310. prr->wType = DNS_TYPE_MX;
  311. prr->Data.MX.wPreference = htons( 10 );
  312. memcpy(
  313. &prr->Data.MX.nameExchange,
  314. &dbname,
  315. SIZEOF_DB_NAME( &dbname ) );
  316. status = convertDottedNameToDbName(
  317. "mail2." PLUGIN_ZONE_NAME,
  318. &dbname ) ;
  319. if ( status != ERROR_SUCCESS )
  320. {
  321. break;
  322. }
  323. prr = g_pDnsAllocate(
  324. sizeof( WORD ) + SIZEOF_DB_NAME( &dbname ) );
  325. CheckNewRRPointer( prr );
  326. prr->wType = DNS_TYPE_MX;
  327. prr->Data.MX.wPreference = htons( 20 );
  328. memcpy(
  329. &prr->Data.MX.nameExchange,
  330. &dbname,
  331. SIZEOF_DB_NAME( &dbname ) );
  332. break;
  333. }
  334. case DNS_TYPE_A:
  335. // At the zone root return 3 arbitrary A records.
  336. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  337. CheckNewRRPointer( prr );
  338. prr->wType = DNS_TYPE_A;
  339. prr->Data.A.ipAddress = inet_addr( "1.1.1.1" );
  340. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  341. CheckNewRRPointer( prr );
  342. prr->wType = DNS_TYPE_A;
  343. prr->Data.A.ipAddress = inet_addr( "2.2.2.2" );
  344. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  345. CheckNewRRPointer( prr );
  346. prr->wType = DNS_TYPE_A;
  347. prr->Data.A.ipAddress = inet_addr( "3.3.3.3" );
  348. break;
  349. default:
  350. status = DNS_PLUGIN_NO_RECORDS;
  351. break;
  352. }
  353. }
  354. else if ( _stricmp( pszQueryName, "www." PLUGIN_ZONE_NAME ) == 0 ||
  355. _stricmp( pszQueryName, "mail1." PLUGIN_ZONE_NAME ) == 0 ||
  356. _stricmp( pszQueryName, "mail2." PLUGIN_ZONE_NAME ) == 0 )
  357. {
  358. if ( wQueryType == DNS_TYPE_A )
  359. {
  360. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  361. CheckNewRRPointer( prr );
  362. prr->wType = DNS_TYPE_A;
  363. prr->Data.A.ipAddress = inet_addr( "100.100.100.1" );
  364. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  365. CheckNewRRPointer( prr );
  366. prr->wType = DNS_TYPE_A;
  367. prr->Data.A.ipAddress = inet_addr( "100.100.100.2" );
  368. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  369. CheckNewRRPointer( prr );
  370. prr->wType = DNS_TYPE_A;
  371. prr->Data.A.ipAddress = inet_addr( "100.100.100.3" );
  372. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  373. CheckNewRRPointer( prr );
  374. prr->wType = DNS_TYPE_A;
  375. prr->Data.A.ipAddress = inet_addr( "100.100.100.4" );
  376. }
  377. else
  378. {
  379. status = DNS_PLUGIN_NO_RECORDS;
  380. }
  381. }
  382. else if ( _stricmp( pszQueryName, "ns1." PLUGIN_ZONE_NAME ) == 0 )
  383. {
  384. if ( wQueryType == DNS_TYPE_A )
  385. {
  386. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  387. CheckNewRRPointer( prr );
  388. prr->wType = DNS_TYPE_A;
  389. prr->Data.A.ipAddress = inet_addr( "100.100.100.50" );
  390. }
  391. else
  392. {
  393. status = DNS_PLUGIN_NO_RECORDS;
  394. }
  395. }
  396. else if ( _stricmp( pszQueryName, "ns2." PLUGIN_ZONE_NAME ) == 0 )
  397. {
  398. if ( wQueryType == DNS_TYPE_A )
  399. {
  400. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  401. CheckNewRRPointer( prr );
  402. prr->wType = DNS_TYPE_A;
  403. prr->Data.A.ipAddress = inet_addr( "100.100.100.51" );
  404. }
  405. else
  406. {
  407. status = DNS_PLUGIN_NO_RECORDS;
  408. }
  409. }
  410. else if ( strstr( pszQueryName, "aaa" ) )
  411. {
  412. //
  413. // For any other queried name in the zone that contains "aaa",
  414. // return an arbitrary A record. Note: using strstr here is
  415. // a bad idea. All string comparisons should be case insensitive.
  416. //
  417. if ( wQueryType == DNS_TYPE_A )
  418. {
  419. prr = g_pDnsAllocate( sizeof( IP4_ADDRESS ) );
  420. CheckNewRRPointer( prr );
  421. prr->wType = DNS_TYPE_A;
  422. prr->Data.A.ipAddress = inet_addr( "1.2.3.4" );
  423. prr->dwTtlSeconds = 1200;
  424. }
  425. else
  426. {
  427. status = DNS_PLUGIN_NO_RECORDS;
  428. }
  429. }
  430. else
  431. {
  432. status = DNS_PLUGIN_NAME_ERROR;
  433. }
  434. Done:
  435. if ( status == DNS_PLUGIN_NO_RECORDS || status == DNS_PLUGIN_NAME_ERROR )
  436. {
  437. //
  438. // Return the zone SOA.
  439. //
  440. DB_NAME dbnamePrimaryServer;
  441. DB_NAME dbnameZoneAdmin;
  442. if ( convertDottedNameToDbName(
  443. "ns1." PLUGIN_ZONE_NAME,
  444. &dbnamePrimaryServer ) != ERROR_SUCCESS )
  445. {
  446. goto Return;
  447. }
  448. if ( convertDottedNameToDbName(
  449. "admin." PLUGIN_ZONE_NAME,
  450. &dbnameZoneAdmin ) != ERROR_SUCCESS )
  451. {
  452. goto Return;
  453. }
  454. prr = g_pDnsAllocate(
  455. sizeof( DWORD ) * 5 +
  456. SIZEOF_DB_NAME( &dbnamePrimaryServer ) +
  457. SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
  458. CheckNewRRPointer( prr );
  459. prr->wType = DNS_TYPE_SOA;
  460. prr->Data.SOA.dwSerialNo = htonl( 1000 );
  461. prr->Data.SOA.dwRefresh = htonl( 3600 );
  462. prr->Data.SOA.dwRetry = htonl( 600 );
  463. prr->Data.SOA.dwExpire = htonl( 1800 );
  464. prr->Data.SOA.dwMinimumTtl = htonl( 60 );
  465. memcpy(
  466. &prr->Data.SOA.namePrimaryServer,
  467. &dbnamePrimaryServer,
  468. SIZEOF_DB_NAME( &dbnamePrimaryServer ) );
  469. memcpy(
  470. ( PBYTE ) &prr->Data.SOA.namePrimaryServer +
  471. SIZEOF_DB_NAME( &dbnamePrimaryServer ),
  472. &dbnameZoneAdmin,
  473. SIZEOF_DB_NAME( &dbnameZoneAdmin ) );
  474. //
  475. // Set owner name for the SOA.
  476. //
  477. if ( pszRecordOwnerName )
  478. {
  479. strcpy( pszRecordOwnerName, PLUGIN_ZONE_NAME );
  480. }
  481. }
  482. else if ( status != ERROR_SUCCESS )
  483. {
  484. PDB_RECORD prrnext;
  485. //
  486. // On failure free any records allocated.
  487. //
  488. for ( prr = *ppDnsRecordListHead; prr; prr = prrnext )
  489. {
  490. prrnext = prr->pRRNext;
  491. g_pDnsFree( prr );
  492. }
  493. *ppDnsRecordListHead = NULL;
  494. }
  495. Return:
  496. return status;
  497. } // DnsPluginQuery