Module: check_mk
Branch: master
Commit: 712b6a52d80bec4ee2f73913b1fe014ab56f47fa
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=712b6a52d80bec…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Fri Jan 4 20:40:46 2019 +0100
7018 Livestatus can now be configured to connect via IPv6
In previous versions it was not possible to connect the GUI to a remote
site via Livestatus using IPv6. This is now possible and can be
configured from the "Distributed Monitoring" configuration.
Technically this was prevented by several smaller things.
The internal Livestatus xinetd configuration now allows ::/0 besides
0.0.0.0 by default. In case you have modified this setting and want to
use IPv6, you may have to add the IPv6 addresses of your choice to this
option.
The site configuration GUI is now able to handle IPv6 addresses
properly.
The internally used livestatus.py Livestatus client implementation
supports IPv6 now.
Livestatus proxy can now connect to Livestatus via IPv6. Added tests for
livestatus proxy connection initiation using the different kind of
sockets.
The cascading livestatus proxy feature, which is used to make the local
unix socket of a site available via the network, can now be used with
IPv6 in addition to the already existing IPv4 support.
Change-Id: I6c9cada5e21cd7d43a9133256a172d36d7db4497
---
.werks/7018 | 26 +++++++++++++++
cmk/gui/watolib.py | 15 ++++++---
livestatus/api/python/livestatus.py | 12 ++++---
.../mk-livestatus/LIVESTATUS_TCP_ONLY_FROM | 6 ++--
tests/unit/livestatus/test_livestatus_unit.py | 38 ++++++++++++++++++++++
5 files changed, 84 insertions(+), 13 deletions(-)
diff --git a/.werks/7018 b/.werks/7018
new file mode 100644
index 0000000..47b5b15
--- /dev/null
+++ b/.werks/7018
@@ -0,0 +1,26 @@
+Title: Livestatus can now be configured to connect via IPv6
+Level: 2
+Component: multisite
+Compatible: compat
+Edition: cre
+Version: 1.6.0i1
+Date: 1546113685
+Class: feature
+
+In previous versions it was not possible to connect the GUI to a remote site
+via Livestatus using IPv6. This is now possible and can be configured from the
+"Distributed Monitoring" configuration.
+
+Technically this was prevented by several smaller things.
+
+The internal Livestatus xinetd configuration now allows ::/0 besides 0.0.0.0 by
+default. In case you have modified this setting and want to use IPv6, you may
+have to add the IPv6 addresses of your choice to this option.
+
+The site configuration GUI is now able to handle IPv6 addresses properly.
+
+The internally used livestatus.py Livestatus client implementation supports
+IPv6 now. Livestatus proxy can now connect to Livestatus via IPv6 and also the
+cascading proxy feature, which is used to make the local unix socket of a site
+available via the network, can now be used with IPv6 in addition to the already
+existing IPv4 support.
diff --git a/cmk/gui/watolib.py b/cmk/gui/watolib.py
index 745738b..4d02163 100644
--- a/cmk/gui/watolib.py
+++ b/cmk/gui/watolib.py
@@ -102,8 +102,9 @@ from cmk.gui.exceptions import MKGeneralException, MKAuthException,
MKUserError,
from cmk.gui.valuespec import (
Dictionary,
Integer,
+ HostAddress,
ListOfStrings,
- IPv4Network,
+ IPNetwork,
Checkbox,
Transform,
DropdownChoice,
@@ -4028,7 +4029,8 @@ class SiteManagement(object):
None,
totext="",
)),
- ("tcp", _("Connect via TCP (IPv4)"),
cls._tcp_socket_valuespec()),
+ ("tcp", _("Connect via TCP (IPv4)"),
cls._tcp_socket_valuespec(ipv6=False)),
+ ("tcp6", _("Connect via TCP (IPv6)"),
cls._tcp_socket_valuespec(ipv6=True)),
("unix", _("Connect via UNIX socket"),
Dictionary(
elements=[
@@ -4044,7 +4046,7 @@ class SiteManagement(object):
return conn_choices
@classmethod
- def _tcp_socket_valuespec(cls):
+ def _tcp_socket_valuespec(cls, ipv6):
return Dictionary(
elements=[
("address",
@@ -4052,10 +4054,12 @@ class SiteManagement(object):
title=_("TCP address to connect to"),
orientation="float",
elements=[
- TextAscii(
+ HostAddress(
label=_("Host:"),
allow_empty=False,
size=15,
+ allow_ipv4_address=not ipv6,
+ allow_ipv6_address=ipv6,
),
Integer(
label=_("Port:"),
@@ -10789,9 +10793,10 @@ class LivestatusViaTCP(Dictionary):
help=_("The access to Livestatus via TCP will only be allowed from
the "
"configured source IP addresses. You can either configure
specific "
"IP addresses or networks in the syntax
<tt>10.3.3.0/24</tt>."),
- valuespec=IPv4Network(),
+ valuespec=IPNetwork(),
orientation="horizontal",
allow_empty=False,
+ default_value=["0.0.0.0", "::/0"],
)),
]
kwargs["optional_keys"] = ["only_from"]
diff --git a/livestatus/api/python/livestatus.py b/livestatus/api/python/livestatus.py
index f458bbc..1b0a70a 100644
--- a/livestatus/api/python/livestatus.py
+++ b/livestatus/api/python/livestatus.py
@@ -317,17 +317,19 @@ class SingleSiteConnection(Helpers):
if family_txt == "unix":
return socket.AF_UNIX, url
- elif family_txt == "tcp":
+ elif family_txt in ["tcp", "tcp6"]:
try:
host, port_txt = url.rsplit(":", 1)
port = int(port_txt)
except ValueError:
- raise MKLivestatusConfigError("Invalid livestatus tcp URL
'%s'. "
- "Correct example is
'tcp:somehost:6557'" % url)
- return socket.AF_INET, (host, port)
+ raise MKLivestatusConfigError(
+ "Invalid livestatus tcp URL '%s'. "
+ "Correct example is 'tcp:somehost:6557' or
'tcp6:somehost:6557'" % url)
+ address_family = socket.AF_INET if family_txt == "tcp" else
socket.AF_INET6
+ return address_family, (host, port)
raise MKLivestatusConfigError("Invalid livestatus URL '%s'. "
- "Must begin with 'tcp:' or
'unix:'" % url)
+ "Must begin with 'tcp:',
'tcp6:' or 'unix:'" % url)
def disconnect(self):
self.socket = None
diff --git a/omd/packages/mk-livestatus/LIVESTATUS_TCP_ONLY_FROM
b/omd/packages/mk-livestatus/LIVESTATUS_TCP_ONLY_FROM
index 7efa9ba..ed77503 100755
--- a/omd/packages/mk-livestatus/LIVESTATUS_TCP_ONLY_FROM
+++ b/omd/packages/mk-livestatus/LIVESTATUS_TCP_ONLY_FROM
@@ -5,12 +5,12 @@
# Description:
# If Livestatus is configured to listen on a TCP port, you
# can configure the IP addresses that are allowed to
-# connect to livestatus here. The setting 0.0.0.0 makes the
-# port available to all clients.
+# connect to livestatus here. The setting "0.0.0.0 ::/0" makes the
+# port available to all IPv4 and IPv6 clients,
case "$1" in
default)
- echo "0.0.0.0"
+ echo "0.0.0.0 ::/0"
;;
choices)
echo
"(?:(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})(/[0-9]{1,2})?\s?)+"
diff --git a/tests/unit/livestatus/test_livestatus_unit.py
b/tests/unit/livestatus/test_livestatus_unit.py
index 49fafec..08347c4 100644
--- a/tests/unit/livestatus/test_livestatus_unit.py
+++ b/tests/unit/livestatus/test_livestatus_unit.py
@@ -1,4 +1,5 @@
import socket
+from contextlib import closing
from pathlib2 import Path
import pytest # type: ignore
@@ -54,11 +55,48 @@ def test_livestatus_local_connection(sock_path):
assert isinstance(live, livestatus.SingleSiteConnection)
+def test_livestatus_ipv4_connection():
+ with closing(socket.socket(socket.AF_INET)) as sock:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # pylint:
disable=no-member
+
+ # Pick a random port
+ sock.bind(("127.0.0.1", 0)) # pylint: disable=no-member
+ port = sock.getsockname()[1] # pylint: disable=no-member
+
+ sock.listen(1) # pylint: disable=no-member
+
+ live = livestatus.SingleSiteConnection("tcp:127.0.0.1:%d" % port)
+ live.connect()
+
+
+def test_livestatus_ipv6_connection():
+ with closing(socket.socket(socket.AF_INET6)) as sock:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # pylint:
disable=no-member
+
+ # Pick a random port
+ try:
+ sock.bind(("::1", 0)) # pylint: disable=no-member
+ except socket.error as e:
+ # Skip this test in case ::1 can not be bound to
+ # (happened in docker container with IPv6 disabled)
+ if e.errno == 99: # Cannot assign requested address
+ pytest.skip("Unable to bind to ::1 (%s)" % e)
+
+ port = sock.getsockname()[1] # pylint: disable=no-member
+
+ sock.listen(1) # pylint: disable=no-member
+
+ live = livestatus.SingleSiteConnection("tcp6:::1:%d" % port)
+ live.connect()
+
+
@pytest.mark.parametrize("socket_url,result", [
("unix:/omd/sites/heute/tmp/run/live", (socket.AF_UNIX,
"/omd/sites/heute/tmp/run/live")),
("unix:/omd/sites/heute/tmp/run/li:ve", (socket.AF_UNIX,
"/omd/sites/heute/tmp/run/li:ve")),
("tcp:127.0.0.1:1234", (socket.AF_INET, ("127.0.0.1", 1234))),
("tcp:126.0.0.1:abc", None),
+ ("tcp6:::1:1234", (socket.AF_INET6, ("::1", 1234))),
+ ("tcp6:::1:abc", None),
("xyz:bla", None),
])
def test_single_site_connection_socketurl(socket_url, result, monkeypatch):