/*++ Copyright (c) 1995-2000 Microsoft Corporation Module Name: DnsCmd.c Abstract: Command line management for DNS Server. Author: Jim Gilroy (jamesg) September 1995 Revision History: Jing Chen (t-jingc) June 1998 Jim Gilroy (jamesg) September 1998 cleanup --*/ #include "dnsclip.h" #include "dnsc_wmi.h" #include // strtoul() #include #include #define DNSCMD_UNICODE 1 // unicode argv interface extern PWSTR getUnicodeForUtf8( IN PSTR pUtf8 ); extern PWSTR utf8ToUnicode( IN PSTR pszInputStr, IN DWORD dwInputLength ); // // Static IP array counts // values beyond any reasonable value anyone would send // #define MAX_IP_PROPERTY_COUNT (200) // // Globals -- allow these to be viewable in processing functions // LPSTR pszServerName = NULL; LPWSTR pwszServerName = NULL; LPSTR pszCommandName = NULL; extern DWORD g_dwViewFlag; BOOL g_UseWmi = FALSE; // // Printing // #define dnscmd_PrintRoutine ((PRINT_ROUTINE) fprintf) #define dnscmd_PrintContext ((PPRINT_CONTEXT) stdout) // // Command table setup // typedef DNS_STATUS ( * COMMAND_FUNCTION )( DWORD argc, PSTR * argv, PWSTR * unicodeArgv ); typedef struct _COMMAND_INFO { LPSTR pszCommandName; COMMAND_FUNCTION pCommandFunction; LPSTR pComments; } COMMAND_INFO, *LPCOMMAND_INFO; // // Command table // extern COMMAND_INFO GlobalCommandInfo[]; // // Dummy Argc to command function to indicate help requested // #define NEED_HELP_ARGC (MAXDWORD) // // Private utilites // COMMAND_FUNCTION getCommandFunction( IN LPSTR pszCommandName ) /*++ Routine Description: Get function corresponding to command name. Arguments: pszCommandName -- command string Return Value: Ptr to command function corresponding to command name. NULL if unrecognized command. --*/ { DWORD i; // // find command in list matching string // i = 0; while( GlobalCommandInfo[i].pszCommandName ) { if( _stricmp( pszCommandName, GlobalCommandInfo[i].pszCommandName ) == 0 ) { return( GlobalCommandInfo[i].pCommandFunction ); } i++; } return NULL; } VOID printCommands( VOID ) { DWORD i = 0; // // display commands // but stop display at "command barrier" (NULL function) // commands below are duplicates or hidden // while( GlobalCommandInfo[i].pszCommandName && GlobalCommandInfo[i].pCommandFunction ) { printf( " %-26s -- %s\n", GlobalCommandInfo[i].pszCommandName, GlobalCommandInfo[i].pComments ); i++; } } LPSTR getCommandName( IN LPSTR pszCmd ) /*++ Routine Description: Get command name. Remove "/" from begining of command. Arguments: pszCmd -- command string Return Value: Ptr to command string (with no leading "/") NULL if not a command. --*/ { if ( pszCmd && ( pszCmd[ 0 ] == '/' || pszCmd[ 0 ] == '-' ) ) { return pszCmd + 1; } return NULL; } BOOL getUserConfirmation( IN LPSTR pszString ) /*++ Routine Description: Get user's confirmation on a command. Arguments: pszString -- configmation string Return Value: TRUE if confirmed. FALSE if cancelled. --*/ { int ch; printf( "Are you sure you want to %s? (y/n) ", pszString ); if ( ( (ch=getchar()) != EOF ) && ( (ch == 'y') || (ch == 'Y') ) ) { printf("\n"); return( TRUE ); } else { printf("\nCommand cancelled!\n"); return( FALSE ); } } DWORD convertDwordParameterUnknownBase( IN LPSTR pszParam ) { INT base = 10; if ( *pszParam > '9' || (*pszParam == '0' && *(pszParam+1) > '9') ) { // hex conversion base = 16; } return strtoul( pszParam, NULL, base ); } DWORD readIpAddressArray( OUT PIP_ADDRESS pAddrArray, IN DWORD ArraySize, IN DWORD Argc, IN LPSTR * Argv, IN BOOL fInaddrNoneAllowed ) /*++ Routine Description: Read IP array. Arguments: pIpArray -- IP array buffer ArraySize -- IPs array can handle Argc -- remaining Argc Argv -- remaining Argv fInaddrNoneAllowed -- if TRUE, 255.255.255.255 is a valid input Return Value: Count of IP in array. --*/ { DWORD count = 0; IP_ADDRESS ip; while ( Argc && count < ArraySize ) { ip = inet_addr( Argv[0] ); // // Allow INADDR_NONE if that address really was specified // and it is allowed as a valid input. // if ( ip == INADDR_NONE && ( !fInaddrNoneAllowed || strcmp( Argv[ 0 ], "255.255.255.255" ) != 0 ) ) { break; } pAddrArray[ count ] = ip; count++; Argc--; Argv++; } return count; } INT ReadArgsIntoDnsTypeArray( OUT PWORD pTypeArray, IN INT ArraySize, IN INT Argc, IN LPSTR * Argv ) /*++ Routine Description: Read list of DNS type strings into a WORD array, one type value per word. The DNS types can be in numeric form or alpha form. e.g. "6" or "SOA" If the types are in alpha form, type strings that cannot be interpreted are not added to the array. DEVNOTE: This is for setting the NoRoundRobin type list, which I have not yet implemented via RPC. Arguments: pIpArray -- IP array buffer ArraySize -- IPs array can handle Argc -- number of arguments Argv -- pointer to arguments Return Value: Number of types successfully processed into array. --*/ { INT typeIdx; for ( typeIdx = 0; Argc && typeIdx < ArraySize; --Argc, ++Argv ) { if ( isdigit( *Argv[ 0 ] ) ) { pTypeArray[ typeIdx++ ] = ( WORD ) atoi( *Argv ); } else { WORD wType; wType = Dns_RecordTypeForName( *Argv, 0 ); // null-terminated if ( wType != 0 ) { pTypeArray[ typeIdx++ ] = wType; } } } return typeIdx; } // ReadArgsIntoDnsTypeArray DWORD parseZoneTypeString( IN LPSTR pszZoneType, OUT BOOL * pfDsIntegrated ) /*++ Routine Description: Get command name. Remove "/" from beggining of command. NULL if error (no "/") Arguments: pszZoneType -- zone type string, e.g. "Secondary" or "2" pfDsIntegrated -- does type indicate zone should be DS integrated? Return Value: DNS_ZONE_TYPE_XXX constant matching zone type or -1 if the type cannot be matched. --*/ { DWORD zoneType = -1; ASSERT( pfDsIntegrated && pszZoneType ); *pfDsIntegrated = FALSE; if ( *pszZoneType == '//' ) { ++pszZoneType; } if ( !_stricmp( pszZoneType, "Primary" ) || !_stricmp( pszZoneType, "1" ) ) { zoneType = DNS_ZONE_TYPE_PRIMARY; } else if ( !_stricmp( pszZoneType, "DsPrimary" ) ) { zoneType = DNS_ZONE_TYPE_PRIMARY; *pfDsIntegrated = TRUE; } else if ( !_stricmp( pszZoneType, "Secondary" ) || !_stricmp( pszZoneType, "2" ) ) { zoneType = DNS_ZONE_TYPE_SECONDARY; } else if ( !_stricmp( pszZoneType, "Stub" ) || !_stricmp( pszZoneType, "3" ) ) { zoneType = DNS_ZONE_TYPE_STUB; } else if ( !_stricmp( pszZoneType, "DsStub" ) ) { zoneType = DNS_ZONE_TYPE_STUB; *pfDsIntegrated = TRUE; } else if ( !_stricmp( pszZoneType, "Forwarder" ) || !_stricmp( pszZoneType, "4" ) ) { zoneType = DNS_ZONE_TYPE_FORWARDER; } else if ( !_stricmp( pszZoneType, "DsForwarder" ) ) { zoneType = DNS_ZONE_TYPE_FORWARDER; *pfDsIntegrated = TRUE; } return zoneType; } BOOL parseDpSpecifier( IN LPSTR pszDpName, OUT DWORD * pdwDpFlag, OPTIONAL OUT LPSTR * ppszCustomDpName ) /*++ Routine Description: Parses a directory partition name. Valid specifiers: /DomainDefault /ForestDefault /Legacy Anything that does not start with "/" is assumed to be the name of a custom DP. If pdwDpFlag is non-NULL, then for a built-in partition ppszCustomDpName will be NULL and the appropriate DWORD flag value will be set at pdwDpFlag. If pdwDpFlag is NULL, then for built-in partitions ppszCustomDpName will be pointed to a static string such as DNS_DP_LEGACY_STR. Arguments: pszDpName - name to be parsed - must be NULL-terminated pdwDpFlag - flag if DP is builtin, zero if custom ppszCustomDpName - set to ptr within pszDpName for customer Return Value: FALSE if the specifier does not appear to be valid (e.g. is empty). --*/ { BOOL rc = TRUE; static const LPSTR pszStaticLegacy = DNS_DP_LEGACY_STR; static const LPSTR pszStaticDomain = DNS_DP_DOMAIN_STR; static const LPSTR pszStaticForest = DNS_DP_FOREST_STR; if ( !ppszCustomDpName || !pszDpName || !*pszDpName ) { rc = FALSE; } else { if ( pdwDpFlag ) { *pdwDpFlag = 0; } *ppszCustomDpName = NULL; if ( *pszDpName == '/' || strncmp( pszDpName, "..", 2 ) == 0 ) { // Skip over preamble character(s). ++pszDpName; if ( *pszDpName == '.' ) { ++pszDpName; } if ( toupper( *pszDpName ) == 'F' ) { if ( pdwDpFlag ) *pdwDpFlag |= DNS_DP_FOREST_DEFAULT; else *ppszCustomDpName = pszStaticForest; } else if ( toupper( *pszDpName ) == 'D' ) { if ( pdwDpFlag ) *pdwDpFlag |= DNS_DP_DOMAIN_DEFAULT; else *ppszCustomDpName = pszStaticDomain; } else if ( toupper( *pszDpName ) == 'L' ) { if ( pdwDpFlag ) *pdwDpFlag |= DNS_DP_LEGACY; else *ppszCustomDpName = pszStaticLegacy; } else { rc = FALSE; } } else { *ppszCustomDpName = pszDpName; } } return rc; } // parseDpSpecifier DWORD readIpArray( OUT PIP_ARRAY pIpArray, IN DWORD ArraySize, IN DWORD Argc, IN LPSTR * Argv ) /*++ Routine Description: Read IP array. Wrapper around readIpAddressArray, to build IP_ARRAY structure. Arguments: pIpArray -- IP array to write into ArraySize -- IPs array can handle Argc -- remaining Argc Argv -- remaining Argv Return Value: Count of IP in array. --*/ { DWORD count; count = readIpAddressArray( pIpArray->AddrArray, ArraySize, Argc, Argv, FALSE ); pIpArray->AddrCount = count; return count; } BOOL readZoneAndDomainName( IN LPSTR * Argv, OUT LPSTR * ppZoneName, OUT LPSTR * ppNodeName, OUT PBOOL pbAllocatedNode, OUT LPSTR * ppZoneArg, OPTIONAL OUT LPSTR * ppNodeArg OPTIONAL ) /*++ Routine Description: Read zone and domain name. Build node FQDN if required. Arguments: Argv -- argv with zone and node names ppZoneName -- addr to receive ptr to zone name ppNodeName -- addr to receive ptr to node name pbAllocatedNode -- ptr to bool set TRUE if allocate node name ppZoneArg -- addr to receive ptr to zone argument ppNodeArg -- addr to receive ptr to node argument Return Value: TRUE -- if in authoritative zone FALSE -- if cache or root hints --*/ { LPSTR pzoneName; LPSTR pnodeName; LPSTR pzoneArg; LPSTR pnodeArg; BOOL ballocated = FALSE; BOOL bauthZone = TRUE; // // read zone name // - special case RootHints and Cache // setting zone to special string // pzoneName = pzoneArg = *Argv; if ( *pzoneArg == '/' ) { if ( _stricmp( pzoneArg, "/RootHints" ) == 0 ) { pzoneName = DNS_ZONE_ROOT_HINTS_A; bauthZone = FALSE; } else if ( _stricmp( pzoneArg, "/Cache" ) == 0 ) { pzoneName = DNS_ZONE_CACHE_A; bauthZone = FALSE; } } else if ( *pzoneArg == '.' ) { if ( _stricmp( pzoneArg, "..RootHints" ) == 0 ) { pzoneName = DNS_ZONE_ROOT_HINTS_A; bauthZone = FALSE; } else if ( _stricmp( pzoneArg, "..Cache" ) == 0 ) { pzoneName = DNS_ZONE_CACHE_A; bauthZone = FALSE; } } Argv++; // // Node name // - for zones, accept file format and append zone name // - root hints or cache must be FQDN // pnodeArg = *Argv; if ( bauthZone ) { if ( strcmp( pnodeArg, "@" ) == 0 ) { pnodeName = pzoneName; } else if ( Dns_IsNameFQDN( pnodeArg ) ) { // input pnodeName is FQDN, with a trailing dot pnodeName = pnodeArg; } else { //append zone name to the end of pnodeName pnodeName = malloc( 2 + strlen(pzoneName) + strlen(pnodeArg) ); if ( pnodeName ) { strcpy ( pnodeName, pnodeArg ); strcat ( pnodeName, "." ); strcat ( pnodeName, pzoneName ); ballocated = TRUE; } } } else { pnodeName = *Argv; } // // set out params // if ( ppZoneName ) { *ppZoneName = pzoneName; } if ( ppNodeName ) { *ppNodeName = pnodeName; } if ( pbAllocatedNode ) { *pbAllocatedNode = ballocated; } if ( ppZoneArg ) { *ppZoneArg = pzoneArg; } if ( ppNodeArg ) { *ppNodeArg = pnodeArg; } return bauthZone; } DNS_STATUS getServerVersion( IN LPWSTR pwszServerName, IN BOOL fPrintVersion, OUT PDWORD pdwMajorVersion, OPTIONAL OUT PDWORD pdwMinorVersion, OPTIONAL OUT PDWORD pdwBuildNum, OPTIONAL OUT PDWORD pdwDomainVersion ) /*++ Routine Description: Query server for version information. Arguments: pwszServerName -- name of DNS server fPrintVersion -- if TRUE this function will print one-line server version pdwMajorVersion -- ptr to DWORD to receive major version or NULL pdwMinorVersion -- ptr to DWORD to receive minor version or NULL pdwBuildNum -- ptr to DWORD to receive build number or NULL pdwDomainVersion -- ptr to DWORD to receive domain behavior version or NULL Return Value: Status code. --*/ { DNS_STATUS status = ERROR_SUCCESS; DWORD dataType; PDNS_RPC_SERVER_INFO pServerInfo = NULL; DWORD dwMajorVersion = 0; DWORD dwMinorVersion = 0; DWORD dwBuildNum = 0; DWORD dwDomainVersion = 0; // // Retrieve server info. // status = DnssrvQuery( pwszServerName, NULL, // zone DNSSRV_QUERY_SERVER_INFO, &dataType, &pServerInfo ); if ( status != ERROR_SUCCESS ) { goto Done; } if ( !pServerInfo || dataType != DNSSRV_TYPEID_SERVER_INFO ) { status = ERROR_NOT_FOUND; goto Done; } // // Parse version. // dwMajorVersion = pServerInfo->dwVersion & 0x000000FF; dwMinorVersion = ( pServerInfo->dwVersion & 0x0000FF00 ) >> 8; dwBuildNum = pServerInfo->dwVersion >> 16; dwDomainVersion = pServerInfo->dwDsDomainVersion; // // Optionally print version. // if ( fPrintVersion ) { printf( "DNS server %S version is %d.%d.%d", pwszServerName, dwMajorVersion, dwMinorVersion, dwBuildNum ); #if DBG printf( ", domain version is %d", dwDomainVersion ); #endif printf( "\n\n" ); } // // Store version numbers to output destinations. // Done: if ( pdwMajorVersion ) { *pdwMajorVersion = dwMajorVersion; } if ( pdwMinorVersion ) { *pdwMinorVersion = dwMinorVersion; } if ( pdwBuildNum ) { *pdwBuildNum = dwBuildNum; } if ( pdwDomainVersion ) { *pdwDomainVersion = dwDomainVersion; } return status; } // getServerVersion DNS_STATUS processCacheSizeQuery( LPWSTR pwszServerName ) /*++ Routine Description: Query server and print current cache usage. Arguments: pwszServerName -- name of DNS server Return Value: Status code. --*/ { DNS_STATUS status = ERROR_SUCCESS; PDNS_RPC_BUFFER pStatBuff = NULL; PDNSSRV_MEMORY_STATS pMemStats = NULL; PDNSSRV_STAT pStat; PCHAR pch; PCHAR pchstop; // // Print server version // getServerVersion( pwszServerName, TRUE, NULL, NULL, NULL, NULL ); // // Retrieve statistics from server. // status = DnssrvGetStatistics( pwszServerName, DNSSRV_STATID_MEMORY, &pStatBuff ); if ( status != ERROR_SUCCESS ) { goto Done; } if ( !pStatBuff ) { printf( "Error: statistics buffer missing\n" ); goto Done; } // // Loop through returned stats to find memory stats. // pch = pStatBuff->Buffer; pchstop = pch + pStatBuff->dwLength; while ( pch < pchstop ) { pStat = ( PDNSSRV_STAT ) pch; pch = ( PCHAR ) GET_NEXT_STAT_IN_BUFFER( pStat ); if ( pch > pchstop ) { printf( "Error: invalid stats buffer\n" ); goto Done; } // printf( "Found stat ID %08X\n", pStat->Header.StatId ); if ( pStat->Header.StatId == DNSSRV_STATID_MEMORY ) { pMemStats = ( PDNSSRV_MEMORY_STATS ) pStat; break; } } if ( pMemStats == NULL ) { printf( "Error: unable to retrieve memory statistics\n" ); status = ERROR_NOT_SUPPORTED; goto Done; } // // Print results. // printf( "Cache usage for server %S is %d bytes:\n" " Nodes: %d (%d bytes)\n" " RRs: %d (%d bytes)\n", pwszServerName, pMemStats->MemTags[ MEMTAG_NODE_CACHE ].Memory + pMemStats->MemTags[ MEMTAG_RECORD_CACHE ].Memory, pMemStats->MemTags[ MEMTAG_NODE_CACHE ].Alloc - pMemStats->MemTags[ MEMTAG_NODE_CACHE ].Free, pMemStats->MemTags[ MEMTAG_NODE_CACHE ].Memory, pMemStats->MemTags[ MEMTAG_RECORD_CACHE ].Alloc - pMemStats->MemTags[ MEMTAG_RECORD_CACHE ].Free, pMemStats->MemTags[ MEMTAG_RECORD_CACHE ].Memory); Done: return status; } // processCacheSizeQuery // // Prototypes for forward references. // DNS_STATUS ProcessDisplayAllZoneRecords( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ); // // DnsCmd entry point // INT __cdecl wmain( IN int argc, IN PWSTR * Argv ) /*++ Routine Description: DnsCmd program entry point. Executes specified command corresponding to a DNS Server API call, using the specified server name. Arguments: argc -- arg count argv -- argument list argv[1] -- DNS ServerName argv[2] -- Command to execute argv[3...] -- arguments to command Return Value: Return from the desired command. Usually a pass through of the return code from DNS API call. --*/ { DNS_STATUS status = ERROR_SUCCESS; COMMAND_FUNCTION pcommandFunc; DWORD commandArgc; LPSTR * commandArgv; LPSTR parg1; WSADATA wsadata; PSTR * argv = NULL; PWSTR * unicodeArgv = Argv; int i; UINT codepage; char achCodepage[12] = ".OCP"; // // Initialize localization stuff - so that printf() of non-US characters // will work properly. I stole this code from dcdiag. // if ( codepage = GetConsoleOutputCP() ) { sprintf( achCodepage, ".%u", codepage ); setlocale( LC_ALL, achCodepage ); } else { // // We do this because LC_ALL sets the LC_CTYPE as well, and we're // not supposed to do that, say the experts if we're setting the // locale to ".OCP". // setlocale( LC_COLLATE, achCodepage ); // sets the sort order setlocale( LC_MONETARY, achCodepage ); // sets the currency formatting rules setlocale( LC_NUMERIC, achCodepage ); // sets the formatting of numerals setlocale( LC_TIME, achCodepage ); // defines the date/time formatting } // // Initialize debug logging. // DnssrvInitializeDebug(); // // Initialize Winsock in case we want to call any Winsock functions. // WSAStartup( MAKEWORD( 2, 0 ), &wsadata ); // // Convert Unicode arguments to UTF8. // argv = ALLOCATE_HEAP( ( argc + 1 ) * sizeof( PCHAR ) ); for ( i = 0; i < argc; ++i ) { argv[ i ] = Dns_NameCopyAllocate( ( PCHAR ) Argv[ i ], 0, // no given length (use strlen) DnsCharSetUnicode, DnsCharSetUtf8 ); } argv[ i ] = NULL; // // DnsCmd [/WMI] [] // // Skip EXE name parameter. // if ( argc < 2 ) { goto Help; } --argc; ++argv; ++unicodeArgv; // // DNS server IP address/name parameter // pszServerName = argv[ 0 ]; if ( *pszServerName == '/' ) { pszServerName = "."; } else { argc--; argv++; unicodeArgv++; } pwszServerName = Dns_NameCopyAllocate( pszServerName, 0, // no given length (use strlen) DnsCharSetUtf8, DnsCharSetUnicode ); // // Check for optional WMI parameter. // if ( argc && argv[ 0 ] && _stricmp( argv[ 0 ], "/WMI" ) == 0 ) { g_UseWmi = TRUE; --argc; ++argv; ++unicodeArgv; if ( argc < 1 ) { goto Help; } status = DnscmdWmi_Initialize( pwszServerName ); if ( status != ERROR_SUCCESS ) { printf( "Fatal error 0x%08X during WMI initialization to server \"%S\"\n", status, pwszServerName ); goto Done; } printf( "Opened WMI connection to server \"%S\"\n\n", pwszServerName ); } // // next parameter is command name, retrieve associated function // if ( argc == 0 ) { status = ERROR_SUCCESS; goto Help; } pszCommandName = argv[0]; pcommandFunc = getCommandFunction( pszCommandName ); if( !pcommandFunc ) { if ( _stricmp( pszCommandName, "/?" ) == 0 || _stricmp( pszCommandName, "/help" ) == 0 ) { status = ERROR_SUCCESS; } else { status = ERROR_INVALID_PARAMETER; printf( "Unknown Command \"%s\" Specified -- type DnsCmd -?.\n", pszCommandName ); } goto Help; } // // set argc, argv for rest of parameters // commandArgc = (DWORD)(argc - 1); commandArgv = &argv[1]; // // test for help request on specific command // - if found, dispatch with Argc=0, to force help // if ( commandArgc > 0 ) { parg1 = commandArgv[0]; if ( *parg1 == '?' || _stricmp( parg1, "/?" ) == 0 || _stricmp( parg1, "/help" ) == 0 ) { commandArgc = NEED_HELP_ARGC; } } // // dispatch to processor for this command // status = pcommandFunc( commandArgc, commandArgv, &unicodeArgv[ 1 ] ); Dns_EndDebug(); if ( commandArgc != NEED_HELP_ARGC && status != ERROR_SUCCESS ) { printf( "\nCommand failed: %s %ld (%08lx)\n", Dns_StatusString( status ), status, status ); if ( status == ERROR_INVALID_PARAMETER ) { printf( "\nCheck the required arguments and format of your command.\n" ); } } else { // // Do not output success message for commands where the output // may be piped to file for a specific use (e.g. zone file output). if ( pcommandFunc != ProcessDisplayAllZoneRecords && commandArgc != NEED_HELP_ARGC ) { printf( "Command completed successfully.\n" ); } } goto Done; // // Output help text. // Help: printf( "\nUsage: DnsCmd []\n\n" ":\n" " IP address or host name -- remote or local DNS server\n" " . -- DNS server on local machine\n" ":\n" ); printCommands(); printf( "\n:\n" " DnsCmd /? -- For help info on specific Command\n" ); // // Cleanup and return. // Done: if ( g_UseWmi ) { DnscmdWmi_Free(); } WSACleanup(); return status; } // // Command Functions // // // Info Query -- for Server or Zone // DNS_STATUS ProcessInfo( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; DWORD typeid; PVOID pdata; LPCSTR pszQueryName; // // /Info [] // // get specific property to query -- if given // if not specific query, default to ZONE_INFO // if ( Argc == 0 ) { pszQueryName = DNSSRV_QUERY_SERVER_INFO; } else if ( Argc == 1 ) { // // Allow property name to be bare or preceded by command char. // pszQueryName = getCommandName( Argv[0] ); if ( !pszQueryName ) { pszQueryName = Argv[ 0 ]; } } else { goto Help; } // // Handle meta-queries: queries that involve client-side parsing // if ( _stricmp( pszQueryName, "CacheSize" ) == 0 ) { status = processCacheSizeQuery( pwszServerName ); } else { // // query, print result on success // if ( g_UseWmi ) { status = DnscmdWmi_ProcessDnssrvQuery( NULL, // zone pszQueryName ); } else { status = DnssrvQuery( pwszServerName, NULL, // no zone pszQueryName, // query name & typeid, & pdata ); if ( status == ERROR_SUCCESS ) { printf( "Query result:\n" ); DnsPrint_RpcUnion( dnscmd_PrintRoutine, dnscmd_PrintContext, NULL, typeid, pdata ); } } if ( status != ERROR_SUCCESS ) { printf( "Info query failed\n" " status = %d (0x%08lx)\n", status, status ); } } return status; Help: printf( "Usage: DnsCmd /Info []\n" " -- server property to view\n" " Examples:\n" " BootMethod\n" " RpcProtocol\n" " LogLevel\n" " EventlogLevel\n" " NoRecursion\n" " ForwardDelegations\n" " ForwardingTimeout\n" " IsSlave\n" " SecureResponses\n" " RecursionRetry\n" " RecursionTimeout\n" " " DNS_REGKEY_ADDITIONAL_RECURSION_TIMEOUT "\n" " MaxCacheTtl\n" " MaxNegativeCacheTtl\n" " RoundRobin\n" " LocalNetPriority\n" " AddressAnswerLimit\n" " BindSecondaries\n" " WriteAuthorityNs\n" " NameCheckFlag\n" " StrictFileParsing\n" " UpdateOptions\n" " DisableAutoReverseZones\n" " SendPort\n" " NoTcp\n" " XfrConnectTimeout\n" " DsPollingInterval\n" " ScavengingInterval\n" " DefaultAgingState\n" " DefaultNoRefreshInterval\n" " DefaultRefreshInterval\n" ); return ERROR_INVALID_PARAMETER; } DNS_STATUS ProcessZoneInfo( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; DWORD typeid; PVOID pdata; LPCSTR pqueryName; // // /ZoneInfo [] // // get specific query -- if given // if not specific query, default to ZONE_INFO // if ( Argc == 1 ) { pqueryName = DNSSRV_QUERY_ZONE_INFO; } else if ( Argc == 2 ) { pqueryName = getCommandName( Argv[1] ); if ( !pqueryName ) { pqueryName = Argv[1]; } } else { goto Help; } // // query, print result on success // if ( g_UseWmi ) { status = DnscmdWmi_ProcessZoneInfo( Argv[ 0 ] ); } else { status = DnssrvQuery( pwszServerName, Argv[0], // zone name pqueryName, // query name &typeid, &pdata ); if ( status == ERROR_SUCCESS ) { printf( "Zone query result:\n" ); DnsPrint_RpcUnion( dnscmd_PrintRoutine, dnscmd_PrintContext, NULL, typeid, pdata ); } else { printf( "Zone info query failed\n" " status = %d (0x%08lx)\n", status, status ); } } return status; Help: printf( "Usage: DnsCmd /ZoneInfo []\n" " -- zone property to view\n" " Examples:\n" " AllowUpdate\n" " DsIntegrated\n" " Aging\n" " RefreshInterval\n" " NoRefreshInterval\n" ); return ERROR_INVALID_PARAMETER; } // // Simple server operations // DNS_STATUS ProcessSimpleServerOperation( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; LPSTR cmd; // // no parameters // Commands: // - DebugBreak // - ClearDebugLog // - Restart // - DisplayCache // - Reload // if ( Argc != 0 ) { printf( "Usage: DnsCmd %s%s\n", ( pszCommandName && *pszCommandName != '/' ) ? "/" : "", pszCommandName ); return ERROR_INVALID_PARAMETER; } if ( g_UseWmi ) { status = DnscmdWmi_ProcessDnssrvOperation( NULL, getCommandName( pszCommandName ), DNSSRV_TYPEID_NULL, ( PVOID ) NULL ); } else { status = DnssrvOperation( pwszServerName, NULL, getCommandName( pszCommandName ), DNSSRV_TYPEID_NULL, NULL ); } if ( status == ERROR_SUCCESS ) { printf( "%s completed successfully.\n", pszServerName ); } else { printf( "%s failed: status = %d (0x%08lx).\n", pszServerName, status, status ); } return status; } DNS_STATUS ProcessAutoConfigure( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; LPSTR cmd; DWORD iarg = 0; DWORD dwflag = 0; while ( iarg < Argc ) { cmd = getCommandName( Argv[ iarg ] ); if ( cmd ) { if ( !_strnicmp( cmd, "For", 3 ) ) { dwflag |= DNS_RPC_AUTOCONFIG_FORWARDERS; } else if ( !_strnicmp( cmd, "Roo", 3 ) ) { dwflag |= DNS_RPC_AUTOCONFIG_ROOTHINTS; } else if ( !_strnicmp( cmd, "Sel", 3 ) ) { dwflag |= DNS_RPC_AUTOCONFIG_SELFPOINTCLIENT; } else { goto Help; } ++iarg; } else { goto Help; } } if ( !dwflag ) { dwflag = DNS_RPC_AUTOCONFIG_SELFPOINTCLIENT | DNS_RPC_AUTOCONFIG_ROOTHINTS | DNS_RPC_AUTOCONFIG_FORWARDERS; } status = DnssrvOperation( pwszServerName, NULL, DNSSRV_OP_AUTO_CONFIGURE, DNSSRV_TYPEID_DWORD, ( PVOID ) ( DWORD_PTR ) dwflag ); if ( status == ERROR_SUCCESS ) { printf( "%s completed successfully.\n", pszServerName ); } else { printf( "%s failed: status = %d (0x%08lx).\n", pszServerName, status, status ); } return status; Help: printf( "Usage: DnsCmd /" DNSSRV_OP_AUTO_CONFIGURE " [Options]\n" " Configures DNS server and client using the current DNS client settings\n" " Options can be on or more of:\n" " /Forwarders -- configure DNS server with forwarders\n" " /RootHints -- configure DNS server with root hints\n" " /SelfPoint -- configure DNS client to point to local DNS server\n" " If no options are specified, default is all options\n" ); return ERROR_INVALID_PARAMETER; } // ProcessAutoConfigure DNS_STATUS ProcessStatistics( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; DWORD statid = DNSSRV_STATID_ALL; // default to all PDNS_RPC_BUFFER pstatsBuf = NULL; LPSTR cmd; // // Statistics [/ | /Clear] // if ( Argc > 1 ) { goto Help; } // // if command -- execute command // /Clear is only supported command // // cmd = getCommandName( Argv[0] ); if ( cmd ) { if ( !_stricmp(cmd, "Clear" ) ) { status = DnssrvOperation( pwszServerName, NULL, "ClearStatistics", DNSSRV_TYPEID_NULL, NULL ); if ( status == ERROR_SUCCESS ) { printf("DNS Server %S statistics cleared.\n", pwszServerName ); } return status; } goto Help; } // // view statistics // - if specific statid given, read it if ( Argc > 0 ) { statid = strtoul( Argv[0], NULL, 16 ); if ( statid == 0 ) { statid = (-1); } } if ( g_UseWmi ) { status = DnscmdWmi_GetStatistics( statid ); } else { status = DnssrvGetStatistics( pwszServerName, statid, & pstatsBuf ); if ( status == ERROR_SUCCESS ) { printf( "DNS Server %S statistics:\n", pwszServerName ); DnsPrint_RpcStatsBuffer( dnscmd_PrintRoutine, dnscmd_PrintContext, NULL, pstatsBuf ); } } return status; Help: printf( "Usage: DnsCmd /Statistics [ | /Clear]\n" " -- ID of particular stat desired. (ALL is the default)\n" " %08lx -- Time \n" " %08lx -- Query \n" " %08lx -- Query2 \n" " %08lx -- Recurse \n" " %08lx -- Master \n" " %08lx -- Secondary \n" " %08lx -- Wins \n" " %08lx -- Wire Update\n" " %08lx -- Security \n" " %08lx -- Ds \n" " %08lx -- Internal Update\n" " %08lx -- Memory \n" " %08lx -- Dbase \n" " %08lx -- Records \n" " %08lx -- PacketMem \n" " /Clear -- clear statistics data\n", DNSSRV_STATID_TIME, DNSSRV_STATID_QUERY, DNSSRV_STATID_QUERY2, DNSSRV_STATID_RECURSE, DNSSRV_STATID_MASTER, DNSSRV_STATID_SECONDARY, DNSSRV_STATID_WINS, DNSSRV_STATID_WIRE_UPDATE, DNSSRV_STATID_SKWANSEC, DNSSRV_STATID_DS, DNSSRV_STATID_NONWIRE_UPDATE, DNSSRV_STATID_MEMORY, DNSSRV_STATID_DBASE, DNSSRV_STATID_RECORD, DNSSRV_STATID_PACKET ); return ERROR_INVALID_PARAMETER; } // // Update server data file(s) // for one zone, when specified // all files: no specified // DNS_STATUS ProcessWriteBackFiles( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; LPSTR zonename = NULL; LPSTR cmd; // // WriteBackFiles [ZoneName] // if ( Argc > 1 ) { goto Help; } if ( Argc == 0 ) { cmd = "WriteDirtyZones"; } else { zonename = Argv[0]; cmd = "WriteBackFile"; } status = DnssrvOperation( pwszServerName, //server zonename, //zone cmd, //cmd DNSSRV_TYPEID_NULL, (PVOID) NULL ); if ( status == ERROR_SUCCESS ) { printf( "Sever data file(s) updated. \n" ); } return status; Help: printf( "Usage: DnsCmd /WriteBackFiles []\n" " -- FQDN of a zone whose datafile to be written back\n" " Default: write back datafile for all dirty zones\n" ); return ERROR_INVALID_PARAMETER; } DNS_STATUS ProcessRecordAdd( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; PDNS_RECORD prr; PDNS_RPC_RECORD prrRpc; LPSTR pzoneName; LPSTR pnodeName; BOOL ballocatedNode; LPSTR pzoneArg; WORD wType; DWORD ttl = 0; DWORD ttlFlag = 0; CHAR buf[33]; DWORD baging = 0; DWORD bopenAcl = 0; // // RecordAdd [/AgeOn | /AgeOff] [/AdminAcl] [] // if ( Argc < 4 || Argc == NEED_HELP_ARGC ) { goto Help; } // // read zone and domain name // readZoneAndDomainName( Argv, & pzoneName, & pnodeName, & ballocatedNode, & pzoneArg, NULL ); Argv++; Argc--; Argv++; Argc--; // // Aging ON\OFF // if ( Argc ) { if ( _stricmp( *Argv, "/Aging" ) == 0 || _stricmp( *Argv, "/AgeOn" ) == 0 ) { baging = 1; Argv++; Argc--; } #if 0 else if ( _stricmp( *Argv, "/AgeOff" ) == 0 ) { baging = 0; Argv++; Argc--; } #endif } if ( Argc && _stricmp( *Argv, "/OpenAcl" ) == 0 ) { bopenAcl = TRUE; Argv++; Argc--; } // // TTL -- optional // - use default if none given // ttl = strtoul( *Argv, NULL, 10 ); if ( ttl == 0 && strcmp(*Argv, "0") != 0 ) { ttlFlag = DNS_RPC_RECORD_FLAG_DEFAULT_TTL; } else // read TTL { Argv++; Argc--; if ( Argc < 1 ) { goto Help; } } // // record type // wType = Dns_RecordTypeForName( *Argv, 0 ); if ( !wType ) { printf( "Invalid RRType: <%s>!\n", *Argv ); goto Help; } Argv++; Argc--; // // build DNS_RECORD // - if no record data, then type delete // - otherwise build record // if ( !Argc ) { prrRpc = ALLOCATE_HEAP( SIZEOF_DNS_RPC_RECORD_HEADER ); if ( !prrRpc ) { printf( "Not enough memory!\n" ); return ERROR_SUCCESS; } prrRpc->wDataLength = 0; prrRpc->wType = wType; } else { prr = Dns_RecordBuild_A( NULL, // ptr to RRSet pnodeName, // nameOwner wType, // RR type in WORD FALSE, // ! S.Delete 0, // S.section Argc, // count of strings Argv // strings to fill into RR ); if ( ! prr ) { printf( "\nInvalid Data!\n" ); goto Help; } // convert DNS_RECORD to RPC buffer prrRpc = DnsConvertRecordToRpcBuffer( prr ); if ( ! prrRpc ) { #if DBG printf("DnsConvertRecordToRpcBuffer() failed\n"); #endif status = GetLastError(); goto Help; } // prr and prrRpc freed by process termination } // // set TTL and flags for the RR // prrRpc->dwTtlSeconds = ttl; prrRpc->dwFlags = ttlFlag; if ( baging ) { prrRpc->dwFlags |= DNS_RPC_RECORD_FLAG_AGING_ON; } if ( bopenAcl ) { prrRpc->dwFlags |= DNS_RPC_FLAG_OPEN_ACL; } if ( g_UseWmi ) { status = DnscmdWmi_ProcessRecordAdd( pzoneName, pnodeName, prrRpc, Argc, Argv ); } else { status = DnssrvUpdateRecord( pwszServerName, // server pzoneName, // zone pnodeName, // node prrRpc, // RR to add NULL ); } if ( status == ERROR_SUCCESS ) { PWSTR pwsznode = getUnicodeForUtf8( pnodeName ); PWSTR pwszzone = getUnicodeForUtf8( pzoneArg ); printf( "Add %s Record for %S at %S\n", *( Argv - 1 ), // RR type pwsznode, // owner name pwszzone ); // zone name FREE_HEAP( pwsznode ); FREE_HEAP( pwszzone ); } // free node name if allocated if ( ballocatedNode ) { free( pnodeName ); } return status; Help: printf( "Usage: DnsCmd /RecordAdd [/Aging] [/OpenAcl]\n" " [] \n\n" " \n" " A \n" " NS,CNAME,MB,MD \n" " PTR,MF,MG,MR \n" " MX,RT,AFSDB \n" " SRV \n" " SOA \n" " \n" " AAAA \n" " TXT []\n" " X25,HINFO,ISDN []\n" " MINFO,RP \n" " WKS []..]\n" " KEY \n" " SIG \n" " \n" " \n" " NXT [...]\n" " WINS \n" " []\n" " WINSR \n" " \n" " -- | /RootHints\n" " -- FQDN of a zone\n" " -- name of node for which a record will be added\n" " - FQDN of a node (name with a '.' at the end) OR\n" " - node name relative to the ZoneName OR\n" " - \"@\" for zone root node OR\n" " - service name for SRV only (e.g. _ftp._tcp)\n" " -- TTL for the RR (Default: TTL defined in SOA)\n" " -- FQDN of a host\n" " -- e.g. 255.255.255.255\n" " -- e.g. 1:2:3:4:5:6:7:8\n" " -- UDP | TCP \n" " -- e.g. domain, smtp\n" " -- type of the RRset signed by this SIG\n" " -- 1=RSA/MD5, 2=Diffie-Hellman, 3=DSA\n" " -- yyyymmddhhmmss - GMT\n" " -- yyyymmddhhmmss - GMT\n" " -- used to discriminate between multiple SIGs\n" " -- domain name of signer\n" " -- 1=TLS, 2=email, 3=DNSSEC, 4=IPSEC\n" " -- KEY or SIG binary data in base64 notation\n" " -- domain name of next RRSet in zone\n" ); return ERROR_INVALID_PARAMETER; } DNS_STATUS ProcessRecordDelete( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) /*++ Routine Description: Delete record(s) from node in zone. --*/ { DNS_STATUS status = ERROR_SUCCESS; PDNS_RECORD prr; PDNS_RPC_RECORD prrRpc = NULL; LPSTR pzoneName = NULL; LPSTR pnodeName = NULL; BOOL ballocatedNode = FALSE; LPSTR pzoneArg; LPSTR psztypeArg = NULL; WORD wType; DWORD ttl = 0; DWORD ttlFlag = 0; CHAR buf[33]; BOOL fconfirm = TRUE; // // RecordDelete [] [/f] // if ( Argc < 3 || Argc == NEED_HELP_ARGC ) { goto Help; } // // Check for "force" (no-confirm) flag // if ( !_stricmp( Argv[Argc-1], "/f" ) ) { fconfirm = FALSE; Argc--; } if ( Argc < 3 ) { goto Help; } // // read zone and domain name // readZoneAndDomainName( Argv, & pzoneName, & pnodeName, & ballocatedNode, & pzoneArg, NULL ); Argv++; Argc--; Argv++; Argc--; // // TTL -- optional // - use default if none given // ttl = strtoul( *Argv, NULL, 10 ); if ( ttl == 0 && strcmp(*Argv, "0") != 0 ) { ttlFlag = DNS_RPC_RECORD_FLAG_DEFAULT_TTL; } else // read TTL { Argv++; Argc--; if ( Argc < 1 ) { goto Help; } } // // record type // psztypeArg = *Argv; wType = Dns_RecordTypeForName( psztypeArg, 0 // null terminated ); if ( !wType ) { printf( "Invalid RRType: <%s>!\n", *Argv ); goto Help; } Argv++; Argc--; // // build DNS_RECORD // - if no record data, then type delete // - otherwise build record // if ( Argc ) { prr = Dns_RecordBuild_A( NULL, // ptr to RRSet pnodeName, // nameOwner wType, // RR type in WORD FALSE, // ! S.Delete 0, // S.section Argc, // count of strings Argv // strings to fill into RR ); if ( ! prr ) { printf( "\nInvalid Data!\n" ); goto Help; } // convert DNS_RECORD to RPC buffer prrRpc = DnsConvertRecordToRpcBuffer( prr ); if ( ! prrRpc ) { #if DBG printf("DnsConvertRecordToRpcBuffer()faild\n"); #endif status = GetLastError(); goto Help; } // prr and prrRpc freed by process termination // set TTL for the RR prrRpc->dwTtlSeconds = ttl; prrRpc->dwFlags = ttlFlag; } // // ask user for confirmation // if ( fconfirm ) { if ( !getUserConfirmation( "delete record" ) ) { return ERROR_SUCCESS; } } // // delete // - if record do full update // - if type do type delete // if ( prrRpc ) { status = DnssrvUpdateRecord( pwszServerName, // server pzoneName, // zone pnodeName, // node NULL, // no add prrRpc // RR to delete ); } else { status = DnssrvDeleteRecordSet( pwszServerName, // server pzoneName, // zone pnodeName, // node wType ); } if ( status == ERROR_SUCCESS ) { printf( "Deleted %s record(s) at %s\n", psztypeArg, pzoneArg ); } // free node name if allocated if ( ballocatedNode && pnodeName ) { free( pnodeName ); } return status; Help: printf( "Usage: DnsCmd /RecordDelete \n" " [/f]\n\n" " -- FQDN of a zone of /RootHints or /Cache\n" " -- name of node from which a record will be deleted\n" " - \"@\" for zone root OR\n" " - FQDN of a node (DNS name with a '.' at the end) OR\n" " - single label for name relative to zone root ) OR\n" " - service name for SRV only (e.g. _ftp._tcp)\n" " : :\n" " A \n" " SRV \n" " AAAA \n" " MX \n" " NS,CNAME,PTR \n" " For help on how to specify the for other record\n" " types see \"DnsCmd /RecordAdd /?\"\n" " If is not specified deletes all records with of specified type\n" " /f -- Execute without asking for confirmation\n\n" ); // free node name if allocated if ( ballocatedNode ) { free( pnodeName ); } return ERROR_INVALID_PARAMETER; } DNS_STATUS ProcessNodeDelete( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) /*++ Routine Description: Delete record(s) from node in zone. --*/ { DNS_STATUS status = ERROR_SUCCESS; LPSTR pzoneName; LPSTR pnodeName; BOOL ballocatedNode = FALSE; LPSTR pzoneArg; DWORD iarg; BOOL bsubtree = FALSE; BOOL bnoConfirm = FALSE; // // /DeleteNode [/Tree] [/f] // if ( Argc < 2 || Argc > 4 ) { goto Help; } // read options iarg = 3; while ( iarg <= Argc ) { if ( !_stricmp(Argv[iarg-1], "/Tree") ) { bsubtree = 1; } else if ( !_stricmp(Argv[iarg-1], "/f") ) { bnoConfirm = 1; } else { goto Help; } iarg ++; } // // if confirmation option, get user confirmation // - if denied, bail // if ( !bnoConfirm ) { PCHAR pmessage = "delete node"; if ( bsubtree ) { pmessage = "delete node's subtree"; } if ( !getUserConfirmation( pmessage ) ) { return ERROR_SUCCESS; } } // // read zone and domain name // readZoneAndDomainName( Argv, & pzoneName, & pnodeName, & ballocatedNode, & pzoneArg, NULL ); // // delete // status = DnssrvDeleteNode( pwszServerName, pzoneName, pnodeName, bsubtree ); if ( status == ERROR_SUCCESS ) { LPWSTR pwsznodeName = utf8ToUnicode( pnodeName, 0 ); printf( "DNS Server %S deleted node at %S:\n" " Status = %d (0x%08lx)\n", pwszServerName, pwsznodeName, status, status ); FREE_HEAP( pwsznodeName ); } // free node name if allocated if ( ballocatedNode ) { free( pnodeName ); } return status; Help: printf( "Usage: DnsCmd /NodeDelete " " [/Tree] [/f]\n" " -- | /RootHints | /Cache\n" " -- FQDN of a zone\n" " -- FQDN of a node (with a '.' at the end) OR\n" " node name relative to the ZoneName\n" " /Tree -- must be provided, when deleting a subdomain;\n" " (Not to delete sub tree is the default)\n" " /f -- execute without asking for confirmation\n" ); return ERROR_INVALID_PARAMETER; } DNS_STATUS ProcessAgeAllRecords( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) /*++ Routine Description: Delete record(s) from node in zone. --*/ { DNS_STATUS status = ERROR_SUCCESS; LPSTR pszzoneName; LPWSTR pwszzoneName; LPSTR pnodeName; BOOL ballocatedNode = FALSE; LPSTR pzoneArg; DWORD iarg; BOOL bsubtree = FALSE; BOOL bnoConfirm = FALSE; // // /AgeAllRecords [] [/f] [Tree] // if ( Argc < 1 || Argc > 4 ) { goto Help; } // // read options // - iarg left at FIRST option parsed // so we can determine if "node" option exists // iarg = Argc; while ( iarg > 1 ) { if ( !_stricmp(Argv[iarg-1], "/Tree") ) { bsubtree = 1; } else if ( !_stricmp(Argv[iarg-1], "/f") ) { bnoConfirm = 1; } else { break; } iarg--; } // // read zone and optionally, domain name // if ( iarg > 1 ) { readZoneAndDomainName( Argv, &pszzoneName, &pnodeName, &ballocatedNode, &pzoneArg, NULL ); } else { pzoneArg = pszzoneName = Argv[ 0 ]; pnodeName = NULL; } pwszzoneName = UnicodeArgv[ 0 ]; // // if confirmation option, get user confirmation // - if denied, bail // if ( !bnoConfirm ) { PCHAR pmessage = "force aging on node"; if ( bsubtree ) { if ( pnodeName ) { pmessage = "force aging on node's subtree"; } else { pmessage = "force aging on entire zone"; } } if ( !getUserConfirmation( pmessage ) ) { return ERROR_SUCCESS; } } // // force aging // status = DnssrvForceAging( pwszServerName, pszzoneName, pnodeName, bsubtree ); if ( status == ERROR_SUCCESS ) { printf( "DNS Server %S forced aging on records %s %s of zone %S:\n" " Status = %d (0x%08lx)\n", pwszServerName, bsubtree ? "in subtree" : "at", pnodeName ? pnodeName : "root", pwszzoneName, status, status ); } // free node name if allocated if ( ballocatedNode ) { free( pnodeName ); } return status; Help: printf( "Usage: DnsCmd /AgeAllRecords [] [/Tree] [/f]\n" " -- \n" " -- FQDN of a zone\n" " -- name or node or subtree in which to enable aging\n" " - \"@\" for zone root OR\n" " - FQDN of a node (name with a '.' at the end) OR\n" " - single label for name relative to zone root\n" " /Tree -- force aging on entire subtree of node\n" " or entire zone if node not given\n" " /f -- execute without asking for confirmation\n" ); return ERROR_INVALID_PARAMETER; } // // Server configuration API // DNS_STATUS ProcessResetProperty( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { DNS_STATUS status = ERROR_SUCCESS; LPSTR pszZone = NULL; LPSTR pszProperty = NULL; BOOL fAllZones = FALSE; // // Config [Zone] // Note: if there is no valid, pass 0 for DWORDs or NULL for // other types. This allows you to clear values, such as the // LogFilterIPList. // if ( Argc < 1 || Argc == NEED_HELP_ARGC ) { goto Help; } // // The first arg is the zone name unless it starts with a // slash, which means the zone name was omitted. // if ( *Argv[ 0 ] != '/' ) { pszZone = Argv[ 0 ]; --Argc; ++Argv; } // // Property name - starts with a slash. // pszProperty = getCommandName( Argv[ 0 ] ); if ( !pszProperty ) { goto Help; } --Argc; ++Argv; // // Trap apply to all zone operation. // if ( pszZone && _stricmp( pszZone, "_ApplyAllZones_" ) == 0 ) { pszZone = NULL; fAllZones = TRUE; } // // Do a strcmp to decide if this is a string or DWORD property. // As more string properties are added we should probably use a // table instead of a bunch of stricmps. // if ( _stricmp( pszProperty, DNS_REGKEY_LOG_FILE_PATH ) == 0 || _stricmp( pszProperty, DNS_REGKEY_ZONE_BREAK_ON_NAME_UPDATE ) == 0 || _stricmp( pszProperty, DNS_REGKEY_SERVER_PLUGIN ) == 0 ) { // // This property is a string value. // LPWSTR pwszPropertyValue = NULL; if ( Argc && Argv[ 0 ] ) { pwszPropertyValue = Dns_StringCopyAllocate( Argv[ 0 ], 0, DnsCharSetUtf8, DnsCharSetUnicode ); } if ( g_UseWmi ) { status = DnscmdWmi_ResetProperty( pszZone, pszProperty, VT_BSTR, ( PVOID ) pwszPropertyValue ); } else { status = DnssrvResetStringProperty( pwszServerName, pszZone, pszProperty, pwszPropertyValue, fAllZones ? DNSSRV_OP_PARAM_APPLY_ALL_ZONES : 0 ); } FREE_HEAP( pwszPropertyValue ); } else if ( _stricmp( pszProperty, DNS_REGKEY_LISTEN_ADDRESSES ) == 0 || _stricmp( pszProperty, DNS_REGKEY_LOG_IP_FILTER_LIST ) == 0 || _stricmp( pszProperty, DNS_REGKEY_FORWARDERS ) == 0 || _stricmp( pszProperty, DNS_REGKEY_ZONE_ALLOW_AUTONS ) == 0 || _stricmp( pszProperty, DNS_REGKEY_ZONE_MASTERS ) == 0 || _stricmp( pszProperty, DNS_REGKEY_ZONE_LOCAL_MASTERS ) == 0 || _stricmp( pszProperty, DNS_REGKEY_ZONE_SCAVENGE_SERVERS ) == 0 || _stricmp( pszProperty, DNS_REGKEY_BREAK_ON_UPDATE_FROM ) == 0 || _stricmp( pszProperty, DNS_REGKEY_BREAK_ON_RECV_FROM ) == 0 ) { // // This property is an IP list value. // DWORD ipCount; IP_ADDRESS ipAddressArray[ MAX_IP_PROPERTY_COUNT ]; PIP_ARRAY pipArray = NULL; if ( Argc ) { BOOL fInaddrNoneAllowed = _stricmp( pszProperty, DNS_REGKEY_BREAK_ON_UPDATE_FROM ) == 0 || _stricmp( pszProperty, DNS_REGKEY_BREAK_ON_RECV_FROM ) == 0; ipCount = readIpAddressArray( ipAddressArray, MAX_IP_PROPERTY_COUNT, Argc, Argv, fInaddrNoneAllowed ); if ( ipCount < 1 ) { goto Help; } Argc -= ipCount; Argv += ipCount; pipArray = Dns_BuildIpArray( ipCount, ipAddressArray ); } if ( g_UseWmi ) { status = DnscmdWmi_ResetProperty( pszZone, pszProperty, PRIVATE_VT_IPARRAY, ( PVOID ) pipArray ); } else { status = DnssrvResetIPListProperty( pwszServerName, pszZone, pszProperty, pipArray, fAllZones ? DNSSRV_OP_PARAM_APPLY_ALL_ZONES : 0 ); } FREE_HEAP( pipArray ); } else { // // This property is a DWORD value. // DWORD value = Argc ? convertDwordParameterUnknownBase( Argv[ 0 ] ) : 0; if ( fAllZones ) { value |= DNSSRV_OP_PARAM_APPLY_ALL_ZONES; } if ( g_UseWmi ) { status = DnscmdWmi_ResetProperty( pszZone, pszProperty, VT_I4, ( PVOID ) ( DWORD_PTR ) value ); } else { status = DnssrvResetDwordProperty( pwszServerName, pszZone, pszProperty, value ); } } if ( status == ERROR_SUCCESS ) { printf( "Registry property %s successfully reset.\n", pszProperty ); } else { printf( "DNS Server failed to reset registry property.\n" " Status = %d (0x%08lx)\n", status, status ); } return status; Help: // Note: removing ..AllZones from help. It doesn't work that well // and it's not a very good model anyways. But leave it in place in // case anyone actually wants to use it. printf( "Usage: DnsCmd /Config " " \n" " Server :\n" " /RpcProtocol\n" " /LogLevel\n" " /" DNS_REGKEY_LOG_FILE_PATH " \n" " /" DNS_REGKEY_LOG_IP_FILTER_LIST " \n" " /" DNS_REGKEY_LOG_FILE_MAX_SIZE "\n" " /EventlogLevel\n" " /NoRecursion\n" " /" DNS_REGKEY_BOOT_METHOD "\n" " /ForwardDelegations\n" " /ForwardingTimeout\n" " /IsSlave\n" " /SecureResponses\n" " /RecursionRetry\n" " /RecursionTimeout\n" " /MaxCacheTtl\n" " /" DNS_REGKEY_MAX_CACHE_SIZE "\n" " /MaxNegativeCacheTtl\n" " /RoundRobin\n" " /LocalNetPriority\n" " /AddressAnswerLimit\n" " /BindSecondaries\n" " /WriteAuthorityNs\n" " /NameCheckFlag\n" " /StrictFileParsing\n" " /UpdateOptions\n" " /DisableAutoReverseZones\n" " /SendPort\n" " /NoTcp\n" " /XfrConnectTimeout\n" " /DsPollingInterval\n" " /DsTombstoneInterval\n" " /ScavengingInterval\n" " /DefaultAgingState\n" " /DefaultNoRefreshInterval\n" " /DefaultRefreshInterval\n" " /" DNS_REGKEY_ENABLE_DNSSEC "\n" " /" DNS_REGKEY_ENABLE_EDNS "\n" " /" DNS_REGKEY_EDNS_CACHE_TIMEOUT "\n" " /" DNS_REGKEY_DISABLE_AUTONS "\n" " Zone :\n" " /SecureSecondaries\n" " /AllowUpdate \n" " -- 0: no updates; 1: unsecure updates; 2: secure updates only\n" " /Aging\n" " /RefreshInterval \n" " /NoRefreshInterval \n" " /" DNS_REGKEY_ZONE_FWD_TIMEOUT " \n" " /" DNS_REGKEY_ZONE_FWD_SLAVE " \n" " /" DNS_REGKEY_ZONE_ALLOW_AUTONS " \n" " : New property value. Use 0x prefix to indicate hex value.\n" " Note some server and zone DWORD properties must be reset as\n" " part of a more complex operation.\n" ); return ERROR_INVALID_PARAMETER; } // ProcessResetProperty DNS_STATUS ProcessResetForwarders( IN DWORD Argc, IN LPSTR * Argv, IN LPWSTR * UnicodeArgv ) { #define MAX_FORWARD_COUNT (50) DNS_STATUS status = ERROR_SUCCESS; DWORD iArg = 0; DWORD fSlave = FALSE; DWORD dwTimeout = DNS_DEFAULT_FORWARD_TIMEOUT; DWORD cForwarders = 0; IP_ADDRESS aipForwarders[ MAX_FORWARD_COUNT ]; LPSTR cmd; // // ResetForwarders [] ...] [/Slave|/NoSlave] [/TimeOut