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"
106 L"All of these options work with the critical threshold \"-c\" too."
112 if (vm.count("version"))
113 std::cout << "Version: " << VERSION << '\n';
115 if (vm.count("warning")) {
117 printInfo.warn = threshold(vm["warning"].as<std::wstring>());
118 } catch (const std::invalid_argument& e) {
119 std::cout << e.what() << '\n';
123 if (vm.count("critical")) {
125 printInfo.crit = threshold(vm["critical"].as<std::wstring>());
126 } catch (const std::invalid_argument& e) {
127 std::cout << e.what() << '\n';
132 l_Debug = vm.count("debug") > 0;
133 l_NoISATAP = vm.count("noisatap") > 0;
138 static int printOutput(printInfoStruct& printInfo, const std::vector<nInterface>& vInterfaces, const std::map<std::wstring, std::wstring>& mapNames)
141 std::wcout << L"Constructing output string" << '\n';
143 long tIn = 0, tOut = 0;
144 std::wstringstream tss;
147 std::map<std::wstring, std::wstring>::const_iterator mapIt;
148 std::wstring wsFriendlyName;
150 for (std::vector<nInterface>::const_iterator it = vInterfaces.begin(); it != vInterfaces.end(); ++it) {
151 tIn += it->BytesInSec;
152 tOut += it->BytesOutSec;
154 std::wcout << "Getting friendly name of " << it->name << '\n';
155 mapIt = mapNames.find(it->name);
156 if (mapIt != mapNames.end()) {
158 std::wcout << "\tIs " << mapIt->second << '\n';
159 wsFriendlyName = mapIt->second;
162 std::wcout << "\tNo friendly name found, using adapter name\n";
163 wsFriendlyName = it->name;
165 if (wsFriendlyName.find(L"isatap") != std::wstring::npos && l_NoISATAP) {
167 std::wcout << "\tSkipping isatap interface " << wsFriendlyName << "\n";
170 boost::algorithm::replace_all(wsFriendlyName, "'", "''");
171 tss << L"'" << wsFriendlyName << L"_in'=" << it->BytesInSec << L"B '" << wsFriendlyName << L"_out'=" << it->BytesOutSec << L"B ";
175 if (printInfo.warn.rend(tIn + tOut))
177 if (printInfo.crit.rend(tIn + tOut))
180 std::wcout << "NETWORK ";
187 std::wcout << L"WARNING";
190 std::wcout << L"CRITICAL";
194 std::wcout << " " << tIn + tOut << L"B/s | "
195 << L"'network'=" << tIn + tOut << L"B;" << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";" << L"0; "
196 << tss.str() << '\n';
201 static int check_network(std::vector<nInterface>& vInterfaces)
205 std::wcout << L"Creating Query and adding counters" << '\n';
207 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValuesIn = NULL, *pDisplayValuesOut = NULL;
210 PDH_STATUS err = PdhOpenQuery(NULL, NULL, &phQuery);
214 const WCHAR *perfIn = L"\\Network Interface(*)\\Bytes Received/sec";
215 PDH_HCOUNTER phCounterIn;
216 err = PdhAddEnglishCounter(phQuery, perfIn, NULL, &phCounterIn);
220 const WCHAR *perfOut = L"\\Network Interface(*)\\Bytes Sent/sec";
221 PDH_HCOUNTER phCounterOut;
222 err = PdhAddEnglishCounter(phQuery, perfOut, NULL, &phCounterOut);
227 std::wcout << L"Collecting first batch of query data" << '\n';
229 err = PdhCollectQueryData(phQuery);
234 std::wcout << L"Sleep for one second" << '\n';
239 std::wcout << L"Collecting second batch of query data" << '\n';
241 err = PdhCollectQueryData(phQuery);
246 std::wcout << L"Creating formatted counter arrays" << '\n';
249 DWORD dwBufferSizeIn = 0;
250 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
251 if (err == PDH_MORE_DATA || SUCCEEDED(err))
252 pDisplayValuesIn = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
256 DWORD dwBufferSizeOut = 0;
257 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
258 if (err == PDH_MORE_DATA || SUCCEEDED(err))
259 pDisplayValuesOut = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwItemCount*dwBufferSizeIn]);
263 err = PdhGetFormattedCounterArray(phCounterIn, PDH_FMT_LONG, &dwBufferSizeIn, &dwItemCount, pDisplayValuesIn);
267 err = PdhGetFormattedCounterArray(phCounterOut, PDH_FMT_LONG, &dwBufferSizeOut, &dwItemCount, pDisplayValuesOut);
272 std::wcout << L"Going over counter array" << '\n';
274 for (DWORD i = 0; i < dwItemCount; i++) {
275 nInterface iface{pDisplayValuesIn[i].szName};
276 iface.BytesInSec = pDisplayValuesIn[i].FmtValue.longValue;
277 iface.BytesOutSec = pDisplayValuesOut[i].FmtValue.longValue;
278 vInterfaces.push_back(iface);
281 std::wcout << L"Collected interface " << pDisplayValuesIn[i].szName << '\n';
285 std::wcout << L"Finished collection. Cleaning up and returning" << '\n';
288 PdhCloseQuery(phQuery);
290 delete reinterpret_cast<BYTE *>(pDisplayValuesIn);
291 delete reinterpret_cast<BYTE *>(pDisplayValuesOut);
297 PdhCloseQuery(phQuery);
299 delete reinterpret_cast<BYTE *>(pDisplayValuesIn);
300 delete reinterpret_cast<BYTE *>(pDisplayValuesOut);
305 static bool mapSystemNamesToFamiliarNames(std::map<std::wstring, std::wstring>& mapNames)
308 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
309 PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
310 PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
311 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsServer = NULL;
312 PIP_ADAPTER_PREFIX pPrefix = NULL;
314 ULONG outBufLen = 15000; //15KB as suggestet by msdn of GetAdaptersAddresses
317 std::wcout << "Mapping adapter system names to friendly names\n";
319 PIP_ADAPTER_ADDRESSES pAddresses;
321 unsigned int Iterations = 0;
325 pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(new BYTE[outBufLen]);
327 dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen);
329 if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
334 } while (++Iterations < 3);
336 if (dwRetVal != NO_ERROR) {
337 std::wcout << "Failed to collect friendly adapter names\n";
342 for (PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next) {
344 std::wcout << "Got: " << pCurrAddresses->Description << " -- " << pCurrAddresses->FriendlyName << '\n';
346 mapNames[pCurrAddresses->Description] = pCurrAddresses->FriendlyName;
353 int wmain(int argc, WCHAR **argv)
355 std::vector<nInterface> vInterfaces;
356 std::map<std::wstring, std::wstring> mapNames;
357 printInfoStruct printInfo;
358 po::variables_map vm;
360 int ret = parseArguments(argc, argv, vm, printInfo);
365 if (!mapSystemNamesToFamiliarNames(mapNames))
368 ret = check_network(vInterfaces);
372 return printOutput(printInfo, vInterfaces, mapNames);