Module: check_mk
Branch: master
Commit: 657228ef6f9af32b06fa9e86bb790eb586f1de37
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=657228ef6f9af3…
Author: Jukka Aro <ja(a)mathias-kettner.de>
Date: Thu Feb 22 15:15:07 2018 +0100
5704 FIX Windows agent: prevent crash without IPv6 support
Windows agent crashed on older systems (at least Windows Server 2003 and
Windows XP) that only supported IPv4.
The bug was introduced in 1.4.0p25. Releases prior to that and as well
as systems that support IPv6 should not have had the bug.
---
.werks/5704 | 18 ++++++++++++++++++
agents/windows/ListenSocket.cc | 4 ++--
agents/windows/ListenSocket.h | 2 +-
agents/windows/WinApi.cc | 8 ++++++++
agents/windows/WinApi.h | 6 ++++++
agents/windows/WinApiAdaptor.h | 7 +++++++
agents/windows/build_version | 2 +-
agents/windows/check_mk_agent.cc | 35 ++++++++++++++++++++++++++++++++---
agents/windows/test/MockWinApi.h | 6 ++++++
9 files changed, 81 insertions(+), 7 deletions(-)
diff --git a/.werks/5704 b/.werks/5704
new file mode 100644
index 0000000..0b49368
--- /dev/null
+++ b/.werks/5704
@@ -0,0 +1,18 @@
+Title: Windows agent: prevent crash without IPv6 support
+Level: 1
+Component: checks
+Compatible: compat
+Edition: cre
+Version: 1.5.0i4
+Date: 1519310458
+Class: fix
+
+Windows agent crashed on older systems (at least Windows Server 2003 and
+Windows XP) that only supported IPv4.
+
+The bug was introduced in 1.4.0p25. Older releases and systems that
+support IPv6 should have remained unaffected.
+
+The configuration option ipv6 was not obeyed. Now this option can be
+set to 'no' in order to only listen IPv4 connections on a IPv6 capable
+system.
diff --git a/agents/windows/ListenSocket.cc b/agents/windows/ListenSocket.cc
index 0ff2678..51a3144 100644
--- a/agents/windows/ListenSocket.cc
+++ b/agents/windows/ListenSocket.cc
@@ -39,10 +39,10 @@ ListenSocket::ListenSocket(int port, const only_from_t
&source_whitelist,
const WinApiAdaptor &winapi)
: _logger(logger)
, _winapi(winapi)
+ , _use_ipv6(supportIPV6)
, _socket(init_listen_socket(port))
, _source_whitelist(source_whitelist)
- , _supports_ipv4(true)
- , _use_ipv6(supportIPV6) {}
+ , _supports_ipv4(true) {}
ListenSocket::~ListenSocket() { _winapi.closesocket(_socket); }
diff --git a/agents/windows/ListenSocket.h b/agents/windows/ListenSocket.h
index 0429f9b..7991444 100644
--- a/agents/windows/ListenSocket.h
+++ b/agents/windows/ListenSocket.h
@@ -55,10 +55,10 @@ private:
Logger *_logger;
const WinApiAdaptor &_winapi;
+ bool _use_ipv6;
SOCKET _socket;
only_from_t _source_whitelist;
bool _supports_ipv4;
- bool _use_ipv6;
};
#endif // ListenSocket_h
diff --git a/agents/windows/WinApi.cc b/agents/windows/WinApi.cc
index 72e9139..86a9309 100644
--- a/agents/windows/WinApi.cc
+++ b/agents/windows/WinApi.cc
@@ -831,6 +831,14 @@ LPSTR WinApi::PathCombine(LPSTR pszDest, LPCSTR pszDir, LPCSTR
pszFile) const {
return ::PathCombineA(pszDest, pszDir, pszFile);
}
+// WSPAPI:
+int WinApi::WSCEnumProtocols(LPINT lpiProtocols,
+ LPWSAPROTOCOL_INFOW lpProtocolBuffer,
+ LPDWORD lpdwBufferLength, LPINT lpErrno) const {
+ return ::WSCEnumProtocols(lpiProtocols, lpProtocolBuffer, lpdwBufferLength,
+ lpErrno);
+}
+
// MISC:
LPWSTR *WinApi::CommandLineToArgvW(LPCWSTR lpCmdLine, int *pNumArgs) const {
return ::CommandLineToArgvW(lpCmdLine, pNumArgs);
diff --git a/agents/windows/WinApi.h b/agents/windows/WinApi.h
index d49bc43..ab7f153 100644
--- a/agents/windows/WinApi.h
+++ b/agents/windows/WinApi.h
@@ -408,6 +408,12 @@ public:
virtual LPSTR PathCombine(LPSTR pszDest, LPCSTR pszDir,
LPCSTR pszFile) const override;
+ // WSPAPI:
+ virtual int WSCEnumProtocols(LPINT lpiProtocols,
+ LPWSAPROTOCOL_INFOW lpProtocolBuffer,
+ LPDWORD lpdwBufferLength,
+ LPINT lpErrno) const override;
+
// MISC:
virtual LPWSTR *CommandLineToArgvW(LPCWSTR lpCmdLine,
int *pNumArgs) const override;
diff --git a/agents/windows/WinApiAdaptor.h b/agents/windows/WinApiAdaptor.h
index 0d6d9bc..b9b9305 100644
--- a/agents/windows/WinApiAdaptor.h
+++ b/agents/windows/WinApiAdaptor.h
@@ -10,6 +10,7 @@
#include <windows.h>
#include <winnt.h>
#include <winsvc.h>
+#include <ws2spi.h>
#include <cstdarg>
#include <cstddef>
#include <cstring>
@@ -442,6 +443,12 @@ public:
virtual LPSTR PathCombine(LPSTR pszDest, LPCSTR pszDir,
LPCSTR pszFile) const = 0;
+ // WSPAPI:
+ virtual int WSCEnumProtocols(LPINT lpiProtocols,
+ LPWSAPROTOCOL_INFOW lpProtocolBuffer,
+ LPDWORD lpdwBufferLength,
+ LPINT lpErrno) const = 0;
+
// MISC:
virtual LPWSTR *CommandLineToArgvW(LPCWSTR lpCmdLine,
int *pNumArgs) const = 0;
diff --git a/agents/windows/build_version b/agents/windows/build_version
index 5fd68c5..63e4f98 100644
--- a/agents/windows/build_version
+++ b/agents/windows/build_version
@@ -1 +1 @@
-3114
+3116
diff --git a/agents/windows/check_mk_agent.cc b/agents/windows/check_mk_agent.cc
index 152f1f8..7349668 100644
--- a/agents/windows/check_mk_agent.cc
+++ b/agents/windows/check_mk_agent.cc
@@ -147,6 +147,8 @@ void RunImmediate(const char *mode, int argc, char **argv);
// '----------------------------------------------------------------------'
namespace {
+const DWORD DEFAULT_BUFFER_SIZE = 16384L;
+
class UnpackError : public std::runtime_error {
public:
UnpackError(const std::string &what) : std::runtime_error(what) {}
@@ -164,10 +166,38 @@ class MillisecondsFormatter : public Formatter {
};
// Ugly but there is no (?) way to pass these as parameters to the Windows
-// service stuff. At least, let us *not* make these yet another global variables
+// service stuff. At least, let us *not* make this yet another global variable
// and access them from other compilation units...
const WinApi s_winapi;
+bool supportIPv6() {
+ INT iNuminfo = 0;
+ DWORD bufferSize = DEFAULT_BUFFER_SIZE;
+ std::vector<BYTE> protocolInfo(bufferSize, 0);
+ int iErrno = 0;
+ auto lpProtocolInfo =
+ reinterpret_cast<LPWSAPROTOCOL_INFOW>(protocolInfo.data());
+
+ while ((iNuminfo = s_winapi.WSCEnumProtocols(nullptr, lpProtocolInfo,
+ &bufferSize, &iErrno)) ==
+ SOCKET_ERROR) {
+ if (iErrno == WSAENOBUFS) {
+ protocolInfo.resize(bufferSize, 0);
+ } else {
+ std::cerr << "WSCEnumProtocols failed with error: " <<
iErrno
+ << std::endl;
+ WSACleanup();
+ exit(1);
+ }
+ }
+
+ for (INT i = 0; i < iNuminfo; ++i) {
+ if (lpProtocolInfo[i].iAddressFamily == AF_INET6) return true;
+ }
+
+ return false;
+}
+
struct GlobalConfig {
Configuration parser;
@@ -191,7 +221,7 @@ struct GlobalConfig {
, section_flush(parser, "global", "section_flush", true,
s_winapi)
, encrypted(parser, "global", "encrypted", false, s_winapi)
, encrypted_rt(parser, "global", "encrypted_rt", true,
s_winapi)
- , support_ipv6(parser, "global", "ipv6", true, s_winapi)
+ , support_ipv6(parser, "global", "ipv6", supportIPv6(),
s_winapi)
, passphrase(parser, "global", "passphrase", "",
s_winapi)
, only_from(parser, "global", "only_from", s_winapi) {}
} * s_config;
@@ -671,7 +701,6 @@ DWORD WINAPI realtime_check_func(void *data_in) {
void do_adhoc(const Environment &env) {
g_should_terminate = false;
Logger *logger = Logger::getLogger("winagent");
-
ListenSocket sock(*s_config->port, *s_config->only_from,
*s_config->support_ipv6, logger, s_winapi);
diff --git a/agents/windows/test/MockWinApi.h b/agents/windows/test/MockWinApi.h
index ffc8e2d..91bdea5 100644
--- a/agents/windows/test/MockWinApi.h
+++ b/agents/windows/test/MockWinApi.h
@@ -442,6 +442,12 @@ public:
MOCK_CONST_METHOD3(PathCombine,
LPSTR(LPSTR pszDest, LPCSTR pszDir, LPCSTR pszFile));
+ // WSPAPI:
+ MOCK_CONST_METHOD4(WSCEnumProtocols,
+ int(LPINT lpiProtocols,
+ LPWSAPROTOCOL_INFOW lpProtocolBuffer,
+ LPDWORD lpdwBufferLength, LPINT lpErrno));
+
// MISC:
MOCK_CONST_METHOD2(CommandLineToArgvW,
LPWSTR *(LPCWSTR lpCmdLine, int *pNumArgs));