/* * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A * PARTICULAR PURPOSE. * * Copyright © Microsoft Corporation. All Rights Reserved. * * Author: Yashlaxmi Gupta * Abstract: * Compares scope-level options for V4 scopes with the same scope address * on 2 DHCP servers (e.g. when configured in an 80:20 configuration) and * highlights the differences. */ #include #include #include #include #include #define SERVERNAME_BUF_SIZE 255 DHCP_IP_ADDRESS GetIpV4Address( __in char *ipAddStr ); DWORD __cdecl main(int argc, char* argv[]) { DWORD error = ERROR_SUCCESS; WCHAR server1[SERVERNAME_BUF_SIZE]={0}, server2[SERVERNAME_BUF_SIZE]={0}; bool mismatch = FALSE; size_t opt1Len = 0, opt2Len = 0; HRESULT Hres = S_OK; DHCP_OPTION_SCOPE_INFO ScopeInfo; LPDHCP_ALL_OPTION_VALUES Values1 = NULL, Values2 = NULL; LPDHCP_OPTION_VALUE Server2OptionValue = NULL, Server1OptionValue = NULL; if (4 != argc) { wprintf(L"Usage: DhcpServerCompareScopesV4.exe "); return ERROR_INVALID_PARAMETER; } MultiByteToWideChar(0, 0, argv[1], (int)strlen(argv[1]), server1, SERVERNAME_BUF_SIZE); MultiByteToWideChar(0, 0, argv[2], (int)strlen(argv[2]), server2, SERVERNAME_BUF_SIZE); DHCP_IP_ADDRESS scopeAddress = GetIpV4Address(argv[3]); ScopeInfo.ScopeType = DhcpSubnetOptions; ScopeInfo.ScopeInfo.SubnetScopeInfo = scopeAddress; // getting all the options configured on server 1 for scope specified. error = DhcpGetAllOptionValues(server1, DHCP_OPT_ENUM_IGNORE_VENDOR, &ScopeInfo, &Values1); if(ERROR_SUCCESS != error) { wprintf(L"DhcpServerCompareScopesV4 returned with error: %d\n",error); return error; } if(NULL != Values1) { // iterating over all the options and option value arrays. for(unsigned int count = 0; count < Values1->NumElements; count++) { if( NULL != Values1->Options[count].OptionsArray ) { // iterating over all the values of a option. for(unsigned int optcount = 0; optcount < Values1->Options[count].OptionsArray->NumElements; optcount++) { // get the option values configured for the specific option ID on second server. // assuming that the scope is already configured on the secondary server. error = DhcpGetOptionValueV5(server2, 0, Values1->Options[count].OptionsArray->Values[optcount].OptionID, NULL, Values1->Options[count].VendorName, &ScopeInfo, &Server2OptionValue); // the option is not configured on the secondary server. if (ERROR_FILE_NOT_FOUND == error) { // there is a mismatch in the scope configurations. wprintf(L"\nMismatch in Option Id %d\n",Values1->Options[count].OptionsArray->Values[optcount].OptionID); wprintf(L"Option Missing in secondary server scope\n"); } // if the option is configured on the secondary server. else if (ERROR_SUCCESS != error) { wprintf(L"DhcpServerCompareScopesV4 returned with error : %d\n",error); return error; } else { // if the number of option values on both servers is same. If not then there is a mismatch. if (Values1->Options[count].OptionsArray->Values[optcount].Value.NumElements != Server2OptionValue->Value.NumElements) { wprintf(L"\nMismatch in Option Id %d\n",Values1->Options[count].OptionsArray->Values[optcount].OptionID); wprintf(L"Number of option values configured on both server scopes differ\n"); } // if the number of options is same, checking the value of options. else { mismatch = FALSE; // iterating over all the values of the option configured for (unsigned int i=0; i < Values1->Options[count].OptionsArray->Values[optcount].Value.NumElements; i++) { // comparing on the basis of option type. switch (Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->OptionType) { case DhcpBinaryDataOption: if(!((Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.BinaryDataOption.DataLength == Server2OptionValue->Value.Elements->Element.BinaryDataOption.DataLength) && (0 == memcmp(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.BinaryDataOption.Data,Server2OptionValue->Value.Elements->Element.BinaryDataOption.Data,Server2OptionValue->Value.Elements->Element.BinaryDataOption.DataLength)))) { mismatch = TRUE; } break; case DhcpByteOption: if(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.ByteOption != Server2OptionValue->Value.Elements->Element.ByteOption) { mismatch = TRUE; } break; case DhcpDWordOption: if(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.DWordOption != Server2OptionValue->Value.Elements->Element.DWordOption) { mismatch = TRUE; } break; case DhcpDWordDWordOption: if ((Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.DWordDWordOption.DWord1 != Server2OptionValue->Value.Elements->Element.DWordDWordOption.DWord1 ) || (Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.DWordDWordOption.DWord2 != Server2OptionValue->Value.Elements->Element.DWordDWordOption.DWord2 ) ) { mismatch = TRUE; } break; case DhcpEncapsulatedDataOption: if (!((Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.EncapsulatedDataOption.DataLength == Server2OptionValue->Value.Elements->Element.EncapsulatedDataOption.DataLength) && (0 == memcmp(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.EncapsulatedDataOption.Data,Server2OptionValue->Value.Elements->Element.EncapsulatedDataOption.Data,Server2OptionValue->Value.Elements->Element.EncapsulatedDataOption.DataLength)))) { mismatch = TRUE; } break; case DhcpIpAddressOption: if (Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.IpAddressOption != Server2OptionValue->Value.Elements->Element.IpAddressOption) { mismatch = TRUE; } break; case DhcpStringDataOption: Hres = StringCchLengthW(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.StringDataOption,STRSAFE_MAX_CCH, &opt1Len); if (FAILED(Hres)) { return HRESULT_CODE(Hres); } Hres = StringCchLengthW(Server2OptionValue->Value.Elements->Element.StringDataOption,STRSAFE_MAX_CCH, &opt2Len); if (FAILED(Hres)) { return HRESULT_CODE(Hres); } if (!((opt1Len == opt2Len)&&(0 == wmemcmp(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.StringDataOption,Server2OptionValue->Value.Elements->Element.StringDataOption,opt1Len)))) { mismatch = TRUE; } break; case DhcpWordOption: if (Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.WordOption != Server2OptionValue->Value.Elements->Element.WordOption) { mismatch = TRUE; } break; case DhcpIpv6AddressOption: Hres = StringCchLengthW(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.Ipv6AddressDataOption,STRSAFE_MAX_CCH, &opt1Len); if (FAILED(Hres)) { return HRESULT_CODE(Hres); } Hres = StringCchLengthW(Server2OptionValue->Value.Elements->Element.Ipv6AddressDataOption,STRSAFE_MAX_CCH, &opt2Len); if (FAILED(Hres)) { return HRESULT_CODE(Hres); } if (!((opt1Len == opt2Len)&&(0 == wmemcmp(Values1->Options[count].OptionsArray->Values[optcount].Value.Elements->Element.Ipv6AddressDataOption,Server2OptionValue->Value.Elements->Element.Ipv6AddressDataOption,opt1Len)))) { mismatch = TRUE; } break; } // if there is a mismatch if (mismatch) { wprintf(L"\nMismatch in Option Id : %d\n",Values1->Options[count].OptionsArray->Values[optcount].OptionID); wprintf(L"Option values on both server scopes differ\n"); break; } } } } if (NULL != Server2OptionValue) { DhcpRpcFreeMemory(Server2OptionValue); Server2OptionValue = NULL; } } } } DhcpRpcFreeMemory(Values1); Values1 = NULL; } // getting all the options configured on the seconday server. // this is to check if there are any options that are configured // on secondary server and missing from the primary server scope. error = DhcpGetAllOptionValues(server2, 1, &ScopeInfo, &Values2); if(ERROR_SUCCESS != error) { wprintf(L"DhcpServerCompareScopesV4 returned with error : %d\n",error); return error; } if(Values2 != NULL) { // iterating over all the options configured. for(unsigned int count = 0; count < Values2->NumElements; count++) { if( NULL != Values2->Options[count].OptionsArray ) { // for each option ID checking if the same is configured on the primary server also. for(unsigned int optcount = 0; optcount < Values2->Options[count].OptionsArray->NumElements; optcount++) { error = DhcpGetOptionValueV5(server1, 0, Values2->Options[count].OptionsArray->Values[optcount].OptionID, NULL, Values2->Options[count].VendorName, &ScopeInfo, &Server1OptionValue ); // if not configured then there is a mismatch. if (ERROR_FILE_NOT_FOUND == error) { wprintf(L"\nMismatch in Option Id %d\n",Values2->Options[count].OptionsArray->Values[optcount].OptionID); wprintf(L"Option Missing in primary server scope\n"); } else if(ERROR_SUCCESS != error) { wprintf(L"DhcpServerCompareScopesV4 returned with error : %d\n",error); return error; } // if the option is configured on primary server, comparing the values would have been done already above. if (NULL != Server1OptionValue) { DhcpRpcFreeMemory(Server1OptionValue); Server1OptionValue = NULL; } } } } DhcpRpcFreeMemory(Values2); Values2 = NULL; } return 0; } DHCP_IP_ADDRESS GetIpV4Address( __in char *ipAddStr ) { DWORD ipAdd = 0, num = 0; size_t Size = 0; int count = 0, base[3] = {1,10,100}, j=0, shift[4]={0,8,16,24}; // find the length of the ip address string. Size = strlen(ipAddStr); for (int i=(int)Size-1; i>=0; i--) { //adding each byte to the ipAdd DWORD if (ipAddStr[i] == '.') { ipAdd = ipAdd + (num << shift[j++]); count = 0; num = 0; i--; } //creating numeric value for each byte. num = num + (ipAddStr[i] - 48) * base[count]; count++; } ipAdd = ipAdd + (num << shift[j]); return ipAdd; }