1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #define WIN32_LEAN_AND_MEAN
5 #include "plugins/thresholds.hpp"
6 #include <boost/program_options.hpp>
7 #include <boost/algorithm/string/replace.hpp>
20 namespace po = boost::program_options;
25 LONG BytesInSec, BytesOutSec;
26 nInterface(std::wstring p)
31 struct printInfoStruct
38 static bool l_NoISATAP;
40 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
42 WCHAR namePath[MAX_PATH];
43 GetModuleFileName(NULL, namePath, MAX_PATH);
44 WCHAR *progName = PathFindFileName(namePath);
46 po::options_description desc("Options");
49 ("help,h", "print usage and exit")
50 ("version,V", "print version and exit")
51 ("debug,d", "Verbose/Debug output")
52 ("noisatap,n", "Don't show ISATAP interfaces in output")
53 ("warning,w", po::wvalue<std::wstring>(), "warning value")
54 ("critical,c", po::wvalue<std::wstring>(), "critical value")
57 po::wcommand_line_parser parser(ac, av);
64 po::command_line_style::unix_style |
65 po::command_line_style::allow_long_disguise)
69 } catch (const std::exception& e) {
70 std::cout << e.what() << '\n' << desc << '\n';
74 if (vm.count("help")) {
75 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
77 L"%s is a simple program to check a machines network performance.\n"
78 L"You can use the following options to define its behaviour:\n\n", progName);
81 L"\nIt will then output a string looking something like this:\n\n"
82 L"\tNETWORK WARNING 1131B/s | network=1131B;1000;7000;0\n\n"
83 L"\"NETWORK\" being the type of the check, \"WARNING\" the returned status\n"
84 L"and \"1131B/s\" is the returned value.\n"
85 L"The performance data is found behind the \"|\", in order:\n"
86 L"returned value, warning threshold, critical threshold, minimal value and,\n"
87 L"if applicable, the maximal value. Performance data will only be displayed when\n"
88 L"you set at least one threshold\n\n"
89 L"This program will also print out additional performance data interface\n"
91 L"%s' exit codes denote the following:\n"
92 L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
93 L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
94 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
95 L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
96 L"Threshold syntax:\n\n"
98 L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
99 L"(unless stated differently)\n\n"
101 L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
103 L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
105 L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
107 L"if the plugin accepts percentage based thresholds those will be used.\n"
108 L"Does nothing if the plugin does not accept percentages, or only uses\n"
109 L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
110 L"to end with a percentage sign.\n\n"
111 L"All of these options work with the critical threshold \"-c\" too."
117 if (vm.count("version"))
118 std::cout << "Version: " << VERSION << '\n';
120 if (vm.count("warning")) {
122 printInfo.warn = threshold(vm["warning"].as<std::wstring>());
123 } catch (const std::invalid_argument& e) {
124 std::cout << e.what() << '\n';
128 if (vm.count("critical")) {
130 printInfo.crit = threshold(vm["critical"].as<std::wstring>());
131 } catch (const std::invalid_argument& e) {
132 std::cout << e.what() << '\n';
137 l_Debug = vm.count("debug") > 0;
138 l_NoISATAP = vm.count("noisatap") > 0;
143 static int printOutput(printInfoStruct& printInfo, const std::vector<nInterface>& vInterfaces, const std::map<std::wstring, std::wstring>& mapNames)
146 std::wcout << L"Constructing output string" << '\n';
148 long tIn = 0, tOut = 0;
149 std::wstringstream tss;
152 std::map<std::wstring, std::wstring>::const_iterator mapIt;
153 std::wstring wsFriendlyName;
155 for (std::vector<nInterface>::const_iterator it = vInterfaces.begin(); it != vInterfaces.end(); ++it) {
156 tIn += it->BytesInSec;
157 tOut += it->BytesOutSec;
159 std::wcout << "Getting friendly name of " << it->name << '\n';
160 mapIt = mapNames.find(it->name);
161 if (mapIt != mapNames.end()) {
163 std::wcout << "\tIs " << mapIt->second << '\n';
164 wsFriendlyName = mapIt->second;
167 std::wcout << "\tNo friendly name found, using adapter name\n";
168 wsFriendlyName = it->name;
170 if (wsFriendlyName.find(L"isatap") != std::wstring::npos && l_NoISATAP) {
172 std::wcout << "\tSkipping isatap interface " << wsFriendlyName << "\n";
175 boost::algorithm::replace_all(wsFriendlyName, "'", "''");
176 tss << L"'" << wsFriendlyName << L"_in'=" << it->BytesInSec << L"B '" << wsFriendlyName << L"_out'=" << it->BytesOutSec << L"B ";
180 if (printInfo.warn.rend(tIn + tOut))
182 if (printInfo.crit.rend(tIn + tOut))
185 std::wcout << "NETWORK ";
192 std::wcout << L"WARNING";
195 std::wcout << L"CRITICAL";
199 std::wcout << " " << tIn + tOut << L"B/s | "
200 << L"'network'=" << tIn + tOut << L"B;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";" << L"0; "
201 << tss.str() << '\n';
206 static int check_network(std::vector<nInterface>& vInterfaces)
210 std::wcout << L"Creating Query and adding counters" << '\n';
212 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValuesIn = NULL, *pDisplayValuesOut = NULL;
215 PDH_STATUS err = PdhOpenQuery(NULL, NULL, &phQuery);
219 const WCHAR *perfIn = L"\\Network Interface(*)\\Bytes Received/sec";
220 PDH_HCOUNTER phCounterIn;
221 err = PdhAddEnglishCounter(phQuery, perfIn, NULL, &phCounterIn);
225 const WCHAR *perfOut = L"\\Network Interface(*)\\Bytes Sent/sec";
226 PDH_HCOUNTER phCounterOut;
227 err = PdhAddEnglishCounter(phQuery, perfOut, NULL, &phCounterOut);
232 std::wcout << L"Collecting first batch of query data" << '\n';
234 err = PdhCollectQueryData(phQuery);
239 std::wcout << L"Sleep for one second" << '\n';
244 std::wcout << L"Collecting second batch of query data" << '\n';
246 err = PdhCollectQueryData(phQuery);
251 std::wcout << L"Creating formatted counter arrays" << '\n';
254 DWORD dwBufferSizeIn = 0;
255 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
256 if (err == PDH_MORE_DATA || SUCCEEDED(err))
257 pDisplayValuesIn = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
261 DWORD dwBufferSizeOut = 0;
262 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
263 if (err == PDH_MORE_DATA || SUCCEEDED(err))
264 pDisplayValuesOut = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
268 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
272 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
277 std::wcout << L"Going over counter array" << '\n';
279 for (DWORD i = 0; i < dwItemCount; i++) {
280 nInterface iface{pDisplayValuesIn[i].szName};
281 iface.BytesInSec = pDisplayValuesIn[i].FmtValue.longValue;
282 iface.BytesOutSec = pDisplayValuesOut[i].FmtValue.longValue;
283 vInterfaces.push_back(iface);
286 std::wcout << L"Collected interface " << pDisplayValuesIn[i].szName << '\n';
290 std::wcout << L"Finished collection. Cleaning up and returning" << '\n';
293 PdhCloseQuery(phQuery);
295 delete reinterpret_cast<BYTE *>(pDisplayValuesIn);
296 delete reinterpret_cast<BYTE *>(pDisplayValuesOut);
302 PdhCloseQuery(phQuery);
304 delete reinterpret_cast<BYTE *>(pDisplayValuesIn);
305 delete reinterpret_cast<BYTE *>(pDisplayValuesOut);
310 static bool mapSystemNamesToFamiliarNames(std::map<std::wstring, std::wstring>& mapNames)
313 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
314 PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
315 PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
316 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServer = NULL;
317 PIP_ADAPTER_PREFIX pPrefix = NULL;
319 ULONG outBufLen = 15000; //15KB as suggestet by msdn of GetAdaptersAddresses
322 std::wcout << "Mapping adapter system names to friendly names\n";
324 PIP_ADAPTER_ADDRESSES pAddresses;
326 unsigned int Iterations = 0;
330 pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(new BYTE[outBufLen]);
332 dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen);
334 if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
339 } while (++Iterations < 3);
341 if (dwRetVal != NO_ERROR) {
342 std::wcout << "Failed to collect friendly adapter names\n";
347 for (PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) {
349 std::wcout << "Got: " << pCurrAddresses->Description << " -- " << pCurrAddresses->FriendlyName << '\n';
351 mapNames[pCurrAddresses->Description] = pCurrAddresses->FriendlyName;
358 int wmain(int argc, WCHAR **argv)
360 std::vector<nInterface> vInterfaces;
361 std::map<std::wstring, std::wstring> mapNames;
362 printInfoStruct printInfo;
363 po::variables_map vm;
365 int ret = parseArguments(argc, argv, vm, printInfo);
370 if (!mapSystemNamesToFamiliarNames(mapNames))
373 ret = check_network(vInterfaces);
377 return printOutput(printInfo, vInterfaces, mapNames);