1 /******************************************************************************
3 * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #define WIN32_LEAN_AND_MEAN
32 #include "check_network.h"
33 #include "boost/algorithm/string/replace.hpp"
37 namespace po = boost::program_options;
39 static BOOL debug = FALSE;
40 static BOOL noisatap = FALSE;
42 INT wmain(INT argc, WCHAR **argv)
44 std::vector<nInterface> vInterfaces;
45 std::map<std::wstring, std::wstring> mapNames;
46 printInfoStruct printInfo{};
49 INT ret = parseArguments(argc, argv, vm, printInfo);
54 if (!mapSystemNamesToFamiliarNames(mapNames))
57 ret = check_network(vInterfaces);
61 return printOutput(printInfo, vInterfaces, mapNames);
64 INT parseArguments(INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
66 WCHAR namePath[MAX_PATH];
67 GetModuleFileName(NULL, namePath, MAX_PATH);
68 WCHAR *progName = PathFindFileName(namePath);
70 po::options_description desc("Options");
73 ("help,h", "print usage and exit")
74 ("version,V", "print version and exit")
75 ("debug,d", "Verbose/Debug output")
76 ("noisatap,n", "Don't show ISATAP interfaces in output")
77 ("warning,w", po::wvalue<std::wstring>(), "warning value")
78 ("critical,c", po::wvalue<std::wstring>(), "critical value")
81 po::basic_command_line_parser<WCHAR> parser(ac, av);
88 po::command_line_style::unix_style |
89 po::command_line_style::allow_long_disguise)
93 } catch (std::exception& e) {
94 std::cout << e.what() << '\n' << desc << '\n';
98 if (vm.count("help")) {
99 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
101 L"%s is a simple program to check a machines network performance.\n"
102 L"You can use the following options to define its behaviour:\n\n", progName);
105 L"\nIt will then output a string looking something like this:\n\n"
106 L"\tNETWORK WARNING 1131B/s | network=1131B;1000;7000;0\n\n"
107 L"\"NETWORK\" being the type of the check, \"WARNING\" the returned status\n"
108 L"and \"1131B/s\" is the returned value.\n"
109 L"The performance data is found behind the \"|\", in order:\n"
110 L"returned value, warning threshold, critical threshold, minimal value and,\n"
111 L"if applicable, the maximal value. Performance data will only be displayed when\n"
112 L"you set at least one threshold\n\n"
113 L"This program will also print out additional performance data interface\n"
115 L"%s' exit codes denote the following:\n"
116 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
117 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
118 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
119 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
120 L"Threshold syntax:\n\n"
122 L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
123 L"(unless stated differently)\n\n"
125 L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
127 L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
129 L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
131 L"if the plugin accepts percentage based thresholds those will be used.\n"
132 L"Does nothing if the plugin does not accept percentages, or only uses\n"
133 L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
134 L"to end with a percentage sign.\n\n"
135 L"All of these options work with the critical threshold \"-c\" too."
141 if (vm.count("version"))
142 std::cout << "Version: " << VERSION << '\n';
144 if (vm.count("warning")) {
146 printInfo.warn = threshold(vm["warning"].as<std::wstring>());
147 } catch (std::invalid_argument& e) {
148 std::cout << e.what() << '\n';
152 if (vm.count("critical")) {
154 printInfo.crit = threshold(vm["critical"].as<std::wstring>());
155 } catch (std::invalid_argument& e) {
156 std::cout << e.what() << '\n';
161 if (vm.count("debug"))
164 if (vm.count("noisatap"))
170 INT printOutput(printInfoStruct& printInfo, CONST std::vector<nInterface>& vInterfaces, CONST std::map<std::wstring, std::wstring>& mapNames)
173 std::wcout << L"Constructing output string" << '\n';
175 long tIn = 0, tOut = 0;
176 std::wstringstream tss, perfDataFirst;
179 std::map<std::wstring, std::wstring>::const_iterator mapIt;
180 std::wstring wsFriendlyName;
182 for (std::vector<nInterface>::const_iterator it = vInterfaces.begin(); it != vInterfaces.end(); ++it) {
183 tIn += it->BytesInSec;
184 tOut += it->BytesOutSec;
186 std::wcout << "Getting friendly name of " << it->name << '\n';
187 mapIt = mapNames.find(it->name);
188 if (mapIt != mapNames.end()) {
190 std::wcout << "\tIs " << mapIt->second << '\n';
191 wsFriendlyName = mapIt->second;
194 std::wcout << "\tNo friendly name found, using adapter name\n";
195 wsFriendlyName = it->name;
197 if(wsFriendlyName.find(L"isatap") != std::wstring::npos && noisatap) {
199 std::wcout << "\tSkipping isatap interface " << wsFriendlyName << "\n";
204 boost::algorithm::replace_all(wsFriendlyName, "'", "''");
205 tss << L"\'" << wsFriendlyName << L"_in\'=" << it->BytesInSec << L"B \'" << wsFriendlyName << L"_out\'=" << it->BytesOutSec << L"B ";
209 if (printInfo.warn.rend(tIn + tOut))
211 if (printInfo.crit.rend(tIn + tOut))
214 perfDataFirst << L"network=" << tIn + tOut << L"B;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";" << L"0; ";
218 std::wcout << L"NETWORK OK " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n';
221 std::wcout << L"NETWORK WARNING " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n';
224 std::wcout << L"NETWORK CRITICAL " << tIn + tOut << L"B/s | " << perfDataFirst.str() << tss.str() << '\n';
231 INT check_network(std::vector <nInterface>& vInterfaces)
233 CONST WCHAR *perfIn = L"\\Network Interface(*)\\Bytes Received/sec";
234 CONST WCHAR *perfOut = L"\\Network Interface(*)\\Bytes Sent/sec";
236 PDH_HQUERY phQuery = NULL;
237 PDH_HCOUNTER phCounterIn, phCounterOut;
238 DWORD dwBufferSizeIn = 0, dwBufferSizeOut = 0, dwItemCount = 0;
239 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValuesIn = NULL, *pDisplayValuesOut = NULL;
243 std::wcout << L"Creating Query and adding counters" << '\n';
245 err = PdhOpenQuery(NULL, NULL, &phQuery);
249 err = PdhAddEnglishCounter(phQuery, perfIn, NULL, &phCounterIn);
253 err = PdhAddEnglishCounter(phQuery, perfOut, NULL, &phCounterOut);
258 std::wcout << L"Collecting first batch of query data" << '\n';
260 err = PdhCollectQueryData(phQuery);
265 std::wcout << L"Sleep for one second" << '\n';
270 std::wcout << L"Collecting second batch of query data" << '\n';
272 err = PdhCollectQueryData(phQuery);
277 std::wcout << L"Creating formatted counter arrays" << '\n';
279 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
280 if (err == PDH_MORE_DATA || SUCCEEDED(err))
281 pDisplayValuesIn = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
285 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
286 if (err == PDH_MORE_DATA || SUCCEEDED(err))
287 pDisplayValuesOut = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
291 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
295 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
300 std::wcout << L"Going over counter array" << '\n';
302 for (DWORD i = 0; i < dwItemCount; i++) {
303 nInterface *iface = new nInterface(std::wstring(pDisplayValuesIn[i].szName));
304 iface->BytesInSec = pDisplayValuesIn[i].FmtValue.longValue;
305 iface->BytesOutSec = pDisplayValuesOut[i].FmtValue.longValue;
306 vInterfaces.push_back(*iface);
308 std::wcout << L"Collected interface " << pDisplayValuesIn[i].szName << '\n';
311 std::wcout << L"Finished collection. Cleaning up and returning" << '\n';
314 PdhCloseQuery(phQuery);
315 if (pDisplayValuesIn)
316 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesIn);
317 if (pDisplayValuesOut)
318 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesOut);
323 PdhCloseQuery(phQuery);
324 if (pDisplayValuesIn)
325 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesIn);
326 if (pDisplayValuesOut)
327 delete reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(pDisplayValuesOut);
331 BOOL mapSystemNamesToFamiliarNames(std::map<std::wstring, std::wstring>& mapNames)
333 DWORD dwSize = 0, dwRetVal = 0;
335 ULONG family = AF_UNSPEC, flags = GAA_FLAG_INCLUDE_PREFIX,
336 outBufLen = 0, Iterations = 0;
337 LPVOID lpMsgBuf = NULL;
339 PIP_ADAPTER_ADDRESSES pAddresses = NULL;
340 PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
342 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
343 PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
344 PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
345 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServer = NULL;
346 PIP_ADAPTER_PREFIX pPrefix = NULL;
348 outBufLen = 15000; //15KB as suggestet by msdn of GetAdaptersAddresses
351 std::wcout << "Mapping adapter system names to friendly names\n";
354 pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(new BYTE[outBufLen]);
356 dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
358 if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
363 } while (++Iterations < 3);
365 if (dwRetVal != NO_ERROR) {
366 std::wcout << "Failed to collect friendly adapter names\n";
371 pCurrAddresses = pAddresses;
372 std::wstringstream wssAdapterName;
373 std::wstringstream wssFriendlyName;
374 for (pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) {
375 wssAdapterName.str(std::wstring());
376 wssFriendlyName.str(std::wstring());
377 wssAdapterName << pCurrAddresses->Description;
378 wssFriendlyName << pCurrAddresses->FriendlyName;
380 std::wcout << "Got: " << wssAdapterName.str() << " -- " << wssFriendlyName.str() << '\n';
382 mapNames.insert(std::pair<std::wstring, std::wstring>(wssAdapterName.str(), wssFriendlyName.str()));