From 9ca19ab041d6618aa0f1b03a4fc8cdf6662e11bf Mon Sep 17 00:00:00 2001 From: Aisha Tammy Date: Thu, 14 Dec 2023 18:37:19 -0500 Subject: [PATCH 1/7] move to utils file --- tests/test_regress_basic.py | 176 +--------------------------------- tests/test_util.py | 183 ++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 173 deletions(-) create mode 100644 tests/test_util.py diff --git a/tests/test_regress_basic.py b/tests/test_regress_basic.py index 5cf7c2c..c817e6f 100644 --- a/tests/test_regress_basic.py +++ b/tests/test_regress_basic.py @@ -1,19 +1,8 @@ -import datetime -import ipaddress -import multiprocessing -import concurrent.futures import os -import tempfile from time import sleep -from unittest import TestCase, mock +from unittest import mock import uuid -from cryptography import x509 -from cryptography.x509.oid import NameOID -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives import hashes, serialization - import ssl import logging import socket @@ -21,168 +10,9 @@ from tlssysloghandler import TLSSysLogHandler -SOCKET_PORT = int(os.environ.get("SOCKET_PORT", 56712)) -SOCKET_TIMEOUT = 5 -SOCKET_BUFFERSIZE = 1024 - -RSA_PUBLIC_EXPONENT = 65537 -RSA_KEY_SIZE = 2048 - -# logger = logging.getLogger(__name__) - - -class TestTLSSysLogHandlerE2E(TestCase): - def setUp(self): - self.tmpdir = tempfile.TemporaryDirectory() - self.queue = multiprocessing.Queue(maxsize=1) - self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=2) - self._generate_keys() - - def tearDown(self): - self.executor.shutdown(wait=True) - self.queue.close() - self.tmpdir.cleanup() - - def _start_server_worker(self, sock_family, sock_type, sock_addr, secure): - if sock_type != socket.SOCK_DGRAM and sock_type != socket.SOCK_STREAM: - raise ValueError( - "sock_type must be socket.SOCK_DGRAM or socket.SOCK_STREAM" - ) - print(f"starting {sock_family} server on {sock_addr} with {sock_type}") - sock = socket.socket(sock_family, sock_type) - print("socket created") - sock.bind(*sock_addr) - print("socket bound at:", sock) - sock.settimeout(SOCKET_TIMEOUT) - print("socket settimeout") - oldsock = None - if sock_type == socket.SOCK_STREAM: - sock.listen(5) - print("socket listening") - if secure: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - print("socket setsockopt") - context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) - print("secure socket context created") - context.load_cert_chain(certfile=self.pub_key, keyfile=self.priv_key) - print("secure socket cert loaded") - oldsock = sock - sock = context.wrap_socket(sock, server_side=True) - print("secure socket listening") - - conn, addr = sock.accept() - print("socket accepted") - conn.settimeout(SOCKET_TIMEOUT) - print("conn socket settimeout") - else: - conn = sock - while True: - print("socket waiting for data") - data = conn.recv(1024) - if not data: - break - print("got data:", data.decode("utf-8")) - self.queue.put(data) - if sock_type == socket.SOCK_STREAM: - conn.close() - sock.close() - if oldsock: - oldsock.close() - - def _start_server(self, sock_family, sock_type, sock_addr, secure=False): - # start a listener on the socket in separate thread using threadpoolexecutor - self.executor.submit( - self._start_server_worker, sock_family, sock_type, sock_addr, secure - ) - sleep(4) - - # https://gist.github.com/bloodearnest/9017111a313777b9cce5 - # Copyright 2018 Simon Davy - # - # Permission is hereby granted, free of charge, to any person obtaining a copy - # of this software and associated documentation files (the "Software"), to deal - # in the Software without restriction, including without limitation the rights - # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - # copies of the Software, and to permit persons to whom the Software is - # furnished to do so, subject to the following conditions: - # - # The above copyright notice and this permission notice shall be included in - # all copies or substantial portions of the Software. - # - # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - # SOFTWARE. - def _generate_selfsigned_cert(self, hostname, ip_addresses=None, key=None): - """Generates self signed certificate for a hostname, and optional IP addresses.""" - # Generate our key - if key is None: - key = rsa.generate_private_key( - public_exponent=65537, - key_size=2048, - backend=default_backend(), - ) - - name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, hostname)]) - - # best practice seem to be to include the hostname in the SAN, which *SHOULD* mean COMMON_NAME is ignored. - alt_names = [x509.DNSName(hostname)] - - # allow addressing by IP, for when you don't have real DNS (common in most testing scenarios - if ip_addresses: - for addr in ip_addresses: - # openssl wants DNSnames for ips... - alt_names.append(x509.DNSName(addr)) - # ... whereas golang's crypto/tls is stricter, and needs IPAddresses - # note: older versions of cryptography do not understand ip_address objects - alt_names.append(x509.IPAddress(ipaddress.ip_address(addr))) - - san = x509.SubjectAlternativeName(alt_names) - - # path_len=0 means this cert can only sign itself, not other certs. - basic_contraints = x509.BasicConstraints(ca=True, path_length=0) - now = datetime.datetime.now() - cert = ( - x509.CertificateBuilder() - .subject_name(name) - .issuer_name(name) - .public_key(key.public_key()) - .serial_number(1000) - .not_valid_before(now) - .not_valid_after(now + datetime.timedelta(days=10 * 365)) - .add_extension(basic_contraints, False) - .add_extension(san, False) - .sign(key, hashes.SHA256(), default_backend()) - ) - cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM) - key_pem = key.private_bytes( - encoding=serialization.Encoding.PEM, - format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=serialization.NoEncryption(), - ) - - return cert_pem, key_pem - - def _generate_keys(self): - pub_key_bytes, priv_key_bytes = self._generate_selfsigned_cert( - "localhost", ["::1", "127.0.0.1"] - ) - - pub_key_path = os.path.join(self.tmpdir.name, "syslog.pub") - priv_key_path = os.path.join(self.tmpdir.name, "syslog.key") - - with open(pub_key_path, "wb") as f: - f.write(pub_key_bytes) - - with open(priv_key_path, "wb") as f: - f.write(priv_key_bytes) - - self.priv_key = priv_key_path - self.pub_key = pub_key_path +from test_util import SOCKET_PORT, TestCertManager +class TestTLSSysLogHandlerE2E(TestCertManager): def _build_logger(self) -> logging.Logger: stack = inspect.stack() logger_name = "{}.{}".format(__name__, stack[1][3]) diff --git a/tests/test_util.py b/tests/test_util.py new file mode 100644 index 0000000..5a77ca4 --- /dev/null +++ b/tests/test_util.py @@ -0,0 +1,183 @@ +import datetime +import ipaddress +import multiprocessing +import concurrent.futures +import os +import tempfile +from time import sleep +from unittest import TestCase, mock +import uuid + +from cryptography import x509 +from cryptography.x509.oid import NameOID +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives import hashes, serialization + +import ssl +import logging +import socket +import inspect + +from tlssysloghandler import TLSSysLogHandler + +SOCKET_PORT = int(os.environ.get("SOCKET_PORT", 56712)) +SOCKET_TIMEOUT = 5 +SOCKET_BUFFERSIZE = 1024 + +RSA_PUBLIC_EXPONENT = 65537 +RSA_KEY_SIZE = 2048 + +# logger = logging.getLogger(__name__) + +class TestCertManager(TestCase): + def setUp(self): + self.tmpdir = tempfile.TemporaryDirectory() + self.queue = multiprocessing.Queue(maxsize=1) + self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=2) + self._generate_keys() + + def tearDown(self): + self.executor.shutdown(wait=True) + self.queue.close() + self.tmpdir.cleanup() + + def _start_server_worker(self, sock_family, sock_type, sock_addr, secure): + if sock_type != socket.SOCK_DGRAM and sock_type != socket.SOCK_STREAM: + raise ValueError( + "sock_type must be socket.SOCK_DGRAM or socket.SOCK_STREAM" + ) + print(f"starting {sock_family} server on {sock_addr} with {sock_type}") + sock = socket.socket(sock_family, sock_type) + print("socket created") + sock.bind(*sock_addr) + print("socket bound at:", sock) + sock.settimeout(SOCKET_TIMEOUT) + print("socket settimeout") + oldsock = None + if sock_type == socket.SOCK_STREAM: + sock.listen(5) + print("socket listening") + if secure: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + print("socket setsockopt") + context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + print("secure socket context created") + context.load_cert_chain(certfile=self.pub_key, keyfile=self.priv_key) + print("secure socket cert loaded") + oldsock = sock + sock = context.wrap_socket(sock, server_side=True) + print("secure socket listening") + + conn, addr = sock.accept() + print("socket accepted") + conn.settimeout(SOCKET_TIMEOUT) + print("conn socket settimeout") + else: + conn = sock + while True: + print("socket waiting for data") + data = conn.recv(1024) + if not data: + break + print("got data:", data.decode("utf-8")) + self.queue.put(data) + if sock_type == socket.SOCK_STREAM: + conn.close() + sock.close() + if oldsock: + oldsock.close() + + def _start_server(self, sock_family, sock_type, sock_addr, secure=False): + # start a listener on the socket in separate thread using threadpoolexecutor + self.executor.submit( + self._start_server_worker, sock_family, sock_type, sock_addr, secure + ) + sleep(4) + + # https://gist.github.com/bloodearnest/9017111a313777b9cce5 + # Copyright 2018 Simon Davy + # + # Permission is hereby granted, free of charge, to any person obtaining a copy + # of this software and associated documentation files (the "Software"), to deal + # in the Software without restriction, including without limitation the rights + # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + # copies of the Software, and to permit persons to whom the Software is + # furnished to do so, subject to the following conditions: + # + # The above copyright notice and this permission notice shall be included in + # all copies or substantial portions of the Software. + # + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + # SOFTWARE. + def _generate_selfsigned_cert(self, hostname, ip_addresses=None, key=None): + """Generates self signed certificate for a hostname, and optional IP addresses.""" + # Generate our key + if key is None: + key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + backend=default_backend(), + ) + + name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, hostname)]) + + # best practice seem to be to include the hostname in the SAN, which *SHOULD* mean COMMON_NAME is ignored. + alt_names = [x509.DNSName(hostname)] + + # allow addressing by IP, for when you don't have real DNS (common in most testing scenarios + if ip_addresses: + for addr in ip_addresses: + # openssl wants DNSnames for ips... + alt_names.append(x509.DNSName(addr)) + # ... whereas golang's crypto/tls is stricter, and needs IPAddresses + # note: older versions of cryptography do not understand ip_address objects + alt_names.append(x509.IPAddress(ipaddress.ip_address(addr))) + + san = x509.SubjectAlternativeName(alt_names) + + # path_len=0 means this cert can only sign itself, not other certs. + basic_contraints = x509.BasicConstraints(ca=True, path_length=0) + now = datetime.datetime.now() + cert = ( + x509.CertificateBuilder() + .subject_name(name) + .issuer_name(name) + .public_key(key.public_key()) + .serial_number(1000) + .not_valid_before(now) + .not_valid_after(now + datetime.timedelta(days=10 * 365)) + .add_extension(basic_contraints, False) + .add_extension(san, False) + .sign(key, hashes.SHA256(), default_backend()) + ) + cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM) + key_pem = key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + + return cert_pem, key_pem + + def _generate_keys(self): + pub_key_bytes, priv_key_bytes = self._generate_selfsigned_cert( + "localhost", ["::1", "127.0.0.1"] + ) + + pub_key_path = os.path.join(self.tmpdir.name, "syslog.pub") + priv_key_path = os.path.join(self.tmpdir.name, "syslog.key") + + with open(pub_key_path, "wb") as f: + f.write(pub_key_bytes) + + with open(priv_key_path, "wb") as f: + f.write(priv_key_bytes) + + self.priv_key = priv_key_path + self.pub_key = pub_key_path From 29e57db5923ee7a84322f5b7cee4256e7c27f7c4 Mon Sep 17 00:00:00 2001 From: Aisha Tammy Date: Thu, 14 Dec 2023 18:42:56 -0500 Subject: [PATCH 2/7] refactor common code --- tests/test_regress_basic.py | 67 +++++++++++++++++++++++++++++-------- tests/test_util.py | 66 ++++++------------------------------ 2 files changed, 64 insertions(+), 69 deletions(-) diff --git a/tests/test_regress_basic.py b/tests/test_regress_basic.py index c817e6f..d18b20f 100644 --- a/tests/test_regress_basic.py +++ b/tests/test_regress_basic.py @@ -4,26 +4,65 @@ import uuid import ssl -import logging import socket -import inspect from tlssysloghandler import TLSSysLogHandler -from test_util import SOCKET_PORT, TestCertManager +from test_util import SOCKET_PORT, SOCKET_TIMEOUT, TestCertManager class TestTLSSysLogHandlerE2E(TestCertManager): - def _build_logger(self) -> logging.Logger: - stack = inspect.stack() - logger_name = "{}.{}".format(__name__, stack[1][3]) - - test_logger = logging.getLogger(logger_name) - test_logger.setLevel(logging.DEBUG) - - for handler in test_logger.handlers: - test_logger.removeHandler(handler) - - return test_logger + def _start_server_worker(self, sock_family, sock_type, sock_addr, secure): + if sock_type != socket.SOCK_DGRAM and sock_type != socket.SOCK_STREAM: + raise ValueError( + "sock_type must be socket.SOCK_DGRAM or socket.SOCK_STREAM" + ) + print(f"starting {sock_family} server on {sock_addr} with {sock_type}") + sock = socket.socket(sock_family, sock_type) + print("socket created") + sock.bind(*sock_addr) + print("socket bound at:", sock) + sock.settimeout(SOCKET_TIMEOUT) + print("socket settimeout") + oldsock = None + if sock_type == socket.SOCK_STREAM: + sock.listen(5) + print("socket listening") + if secure: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + print("socket setsockopt") + context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + print("secure socket context created") + context.load_cert_chain(certfile=self.pub_key, keyfile=self.priv_key) + print("secure socket cert loaded") + oldsock = sock + sock = context.wrap_socket(sock, server_side=True) + print("secure socket listening") + + conn, addr = sock.accept() + print("socket accepted") + conn.settimeout(SOCKET_TIMEOUT) + print("conn socket settimeout") + else: + conn = sock + while True: + print("socket waiting for data") + data = conn.recv(1024) + if not data: + break + print("got data:", data.decode("utf-8")) + self.queue.put(data) + if sock_type == socket.SOCK_STREAM: + conn.close() + sock.close() + if oldsock: + oldsock.close() + + def _start_server(self, sock_family, sock_type, sock_addr, secure=False): + # start a listener on the socket in separate thread using threadpoolexecutor + self.executor.submit( + self._start_server_worker, sock_family, sock_type, sock_addr, secure + ) + sleep(4) def test_e2e_unix_DGRAM(self): self.socket_path = os.path.join(self.tmpdir.name, "syslog.sock") diff --git a/tests/test_util.py b/tests/test_util.py index 5a77ca4..2c57fbd 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -14,12 +14,9 @@ from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import hashes, serialization -import ssl import logging -import socket import inspect -from tlssysloghandler import TLSSysLogHandler SOCKET_PORT = int(os.environ.get("SOCKET_PORT", 56712)) SOCKET_TIMEOUT = 5 @@ -42,58 +39,17 @@ def tearDown(self): self.queue.close() self.tmpdir.cleanup() - def _start_server_worker(self, sock_family, sock_type, sock_addr, secure): - if sock_type != socket.SOCK_DGRAM and sock_type != socket.SOCK_STREAM: - raise ValueError( - "sock_type must be socket.SOCK_DGRAM or socket.SOCK_STREAM" - ) - print(f"starting {sock_family} server on {sock_addr} with {sock_type}") - sock = socket.socket(sock_family, sock_type) - print("socket created") - sock.bind(*sock_addr) - print("socket bound at:", sock) - sock.settimeout(SOCKET_TIMEOUT) - print("socket settimeout") - oldsock = None - if sock_type == socket.SOCK_STREAM: - sock.listen(5) - print("socket listening") - if secure: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - print("socket setsockopt") - context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) - print("secure socket context created") - context.load_cert_chain(certfile=self.pub_key, keyfile=self.priv_key) - print("secure socket cert loaded") - oldsock = sock - sock = context.wrap_socket(sock, server_side=True) - print("secure socket listening") - - conn, addr = sock.accept() - print("socket accepted") - conn.settimeout(SOCKET_TIMEOUT) - print("conn socket settimeout") - else: - conn = sock - while True: - print("socket waiting for data") - data = conn.recv(1024) - if not data: - break - print("got data:", data.decode("utf-8")) - self.queue.put(data) - if sock_type == socket.SOCK_STREAM: - conn.close() - sock.close() - if oldsock: - oldsock.close() - - def _start_server(self, sock_family, sock_type, sock_addr, secure=False): - # start a listener on the socket in separate thread using threadpoolexecutor - self.executor.submit( - self._start_server_worker, sock_family, sock_type, sock_addr, secure - ) - sleep(4) + def _build_logger(self) -> logging.Logger: + stack = inspect.stack() + logger_name = "{}.{}".format(__name__, stack[1][3]) + + test_logger = logging.getLogger(logger_name) + test_logger.setLevel(logging.DEBUG) + + for handler in test_logger.handlers: + test_logger.removeHandler(handler) + + return test_logger # https://gist.github.com/bloodearnest/9017111a313777b9cce5 # Copyright 2018 Simon Davy From d6efaf773eec924409cfa059b1bcdaf378d7aa75 Mon Sep 17 00:00:00 2001 From: Aisha Tammy Date: Thu, 14 Dec 2023 20:32:19 -0500 Subject: [PATCH 3/7] add syslogng tests --- tests/test_regress_basic.py | 6 +- tests/test_regress_syslogng.py | 412 +++++++++++++++++++++++++++++++++ tests/test_util.py | 8 +- 3 files changed, 420 insertions(+), 6 deletions(-) create mode 100644 tests/test_regress_syslogng.py diff --git a/tests/test_regress_basic.py b/tests/test_regress_basic.py index d18b20f..02d7a48 100644 --- a/tests/test_regress_basic.py +++ b/tests/test_regress_basic.py @@ -8,7 +8,11 @@ from tlssysloghandler import TLSSysLogHandler -from test_util import SOCKET_PORT, SOCKET_TIMEOUT, TestCertManager +from test_util import SOCKET_PORT, TestCertManager + +SOCKET_TIMEOUT = 5 +SOCKET_BUFFERSIZE = 1024 + class TestTLSSysLogHandlerE2E(TestCertManager): def _start_server_worker(self, sock_family, sock_type, sock_addr, secure): diff --git a/tests/test_regress_syslogng.py b/tests/test_regress_syslogng.py new file mode 100644 index 0000000..77a6e02 --- /dev/null +++ b/tests/test_regress_syslogng.py @@ -0,0 +1,412 @@ +import os +import socket +import subprocess +from time import sleep +import unittest +import uuid + +from tlssysloghandler import TLSSysLogHandler + +from test_util import SOCKET_PORT, TestCertManager + +SOCKET_PORT4_DGRAM = SOCKET_PORT +SOCKET_PORT4_STREAM = SOCKET_PORT + 1 +SOCKET_PORT4_TLS = SOCKET_PORT + 2 +SOCKET_PORT6_DGRAM = SOCKET_PORT + 3 +SOCKET_PORT6_STREAM = SOCKET_PORT + 4 +SOCKET_PORT6_TLS = SOCKET_PORT + 5 +SOCKET_PORT4_MUTUAL_TLS = SOCKET_PORT + 6 +SOCKET_PORT6_MUTUAL_TLS = SOCKET_PORT + 7 + + +# check if syslog-ng is installed else skip tests +try: + subprocess.check_output(["syslog-ng", "--version"]) +except FileNotFoundError: + raise unittest.SkipTest("syslog-ng not installed") + + +class TestSyslogNG(TestCertManager): + def _start_server(self, ip): + # create syslog-ng tls config + config = """ +@version: 4.4 +@include "scl.conf" + +source unix_dgram {{ + unix-dgram("{0}/syslog-dgram.sock"); +}}; +source unix_stream {{ + unix-stream("{0}/syslog-stream.sock"); +}}; +source net4_dgram {{ + network( + ip("127.0.0.1") + transport("udp") + port({1}) + ); +}}; +source net4_stream {{ + network( + ip("127.0.0.1") + transport("tcp") + port({2}) + ); +}}; +source net4_tls {{ + network( + ip("127.0.0.1") + transport("tls") + port({3}) + tls( + key-file("{0}/syslog.key") + cert-file("{0}/syslog.pub") + peer-verify(optional-untrusted) + ) + ); +}}; +source net6_dgram {{ + network( + ip("::1") + ip-protocol(6) + transport("udp") + port({4}) + ); +}}; +source net6_stream {{ + network( + ip("::1") + ip-protocol(6) + transport("tcp") + port({5}) + ); +}}; +source net6_tls {{ + network( + ip("::1") + ip-protocol(6) + transport("tls") + port({6}) + tls( + key-file("{0}/syslog.key") + cert-file("{0}/syslog.pub") + peer-verify(optional-untrusted) + ) + ); +}}; +source net4_mutual_tls {{ + network( + ip("127.0.0.1") + transport("tls") + port({7}) + tls( + key-file("{0}/syslog.key") + cert-file("{0}/syslog.pub") + peer-verify(required-trusted) + ) + ); +}}; +source net6_mutual_tls {{ + network( + ip("::1") + ip-protocol(6) + transport("tls") + port({8}) + tls( + key-file("{0}/syslog.key") + cert-file("{0}/syslog.pub") + peer-verify(required-trusted) + ) + ); +}}; + + +destination all {{ + file("{0}/syslog.log"); +}}; + +filter f_messages {{ level(debug..crit) }}; + +log {{ + source(unix_dgram); + filter(f_messages); + destination(all); +}}; +log {{ + source(unix_stream); + filter(f_messages); + destination(all); +}}; +log {{ + source(net4_dgram); + filter(f_messages); + destination(all); +}}; +log {{ + source(net4_stream); + filter(f_messages); + destination(all); +}}; +log {{ + source(net4_tls); + filter(f_messages); + destination(all); +}}; +log {{ + source(net6_dgram); + filter(f_messages); + destination(all); +}}; +log {{ + source(net6_stream); + filter(f_messages); + destination(all); +}}; +log {{ + source(net6_tls); + filter(f_messages); + destination(all); +}}; +log {{ + source(net4_mutual_tls); + filter(f_messages); + destination(all); +}}; +log {{ + source(net6_mutual_tls); + filter(f_messages); + destination(all); +}}; + """ + + config = config.format( + self.tmpdir.name, + SOCKET_PORT4_DGRAM, + SOCKET_PORT4_STREAM, + SOCKET_PORT4_TLS, + SOCKET_PORT6_DGRAM, + SOCKET_PORT6_STREAM, + SOCKET_PORT6_TLS, + SOCKET_PORT4_MUTUAL_TLS, + SOCKET_PORT6_MUTUAL_TLS, + ) + + config_path = os.path.join(self.tmpdir.name, "syslog-ng.conf") + with open(config_path, "w") as f: + f.write(config) + + # create output file + open(os.path.join(self.tmpdir.name, "syslog.log"), "w").close() + + # generate certificates + self._generate_keys() + + # start syslog-ng + command = [ + "syslog-ng", + "-F", + "-d", + "-f", + config_path, + "--persist-file", + f"{self.tmpdir.name}/syslog-ng.persist-", + "--pidfile", + f"{self.tmpdir.name}/syslog-ng.pid", + "--control", + f"{self.tmpdir.name}/syslog-ng.ctl", + ] + + self.server_pid = subprocess.Popen( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=self.tmpdir.name, + ) + + # wait for syslog-ng to start + sleep(1) + + def _stop_server(self): + self.server_pid.kill() + self.server_pid.wait() + + def test_syslogng_inet_DGRAM(self): + self._start_server("127.0.0.1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=("127.0.0.1", SOCKET_PORT4_DGRAM), socktype=socket.SOCK_DGRAM + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_syslogng_inet_STREAM(self): + self._start_server("127.0.0.1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=("127.0.0.1", SOCKET_PORT4_STREAM), socktype=socket.SOCK_STREAM + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_syslogng_inet_TLS(self): + self._start_server("127.0.0.1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=("127.0.0.1", SOCKET_PORT4_TLS), + socktype=socket.SOCK_STREAM, + secure={"cafile": self.tmpdir.name + "/syslog.pub"}, + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_syslogng_unix_DGRAM(self): + self._start_server("127.0.0.1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=self.tmpdir.name + "/syslog-dgram.sock", socktype=socket.SOCK_DGRAM + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_syslogng_unix_STREAM(self): + self._start_server("127.0.0.1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=self.tmpdir.name + "/syslog-stream.sock", + socktype=socket.SOCK_STREAM, + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_syslogng_inet6_DGRAM(self): + self._start_server("::1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=("::1", SOCKET_PORT6_DGRAM), socktype=socket.SOCK_DGRAM + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_syslogng_inet6_STREAM(self): + self._start_server("::1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=("::1", SOCKET_PORT6_STREAM), socktype=socket.SOCK_STREAM + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_syslogng_inet6_TLS(self): + self._start_server("::1") + + test_logger = self._build_logger() + + handler = TLSSysLogHandler( + address=("::1", SOCKET_PORT6_TLS), + socktype=socket.SOCK_STREAM, + secure={"cafile": self.tmpdir.name + "/syslog.pub"}, + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() diff --git a/tests/test_util.py b/tests/test_util.py index 2c57fbd..000c739 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -5,8 +5,7 @@ import os import tempfile from time import sleep -from unittest import TestCase, mock -import uuid +from unittest import TestCase from cryptography import x509 from cryptography.x509.oid import NameOID @@ -19,14 +18,13 @@ SOCKET_PORT = int(os.environ.get("SOCKET_PORT", 56712)) -SOCKET_TIMEOUT = 5 -SOCKET_BUFFERSIZE = 1024 RSA_PUBLIC_EXPONENT = 65537 RSA_KEY_SIZE = 2048 # logger = logging.getLogger(__name__) + class TestCertManager(TestCase): def setUp(self): self.tmpdir = tempfile.TemporaryDirectory() @@ -37,7 +35,7 @@ def setUp(self): def tearDown(self): self.executor.shutdown(wait=True) self.queue.close() - self.tmpdir.cleanup() + # self.tmpdir.cleanup() def _build_logger(self) -> logging.Logger: stack = inspect.stack() From 7749ed4ebe0a4bb9e9dba12f40ad3a7ff8515564 Mon Sep 17 00:00:00 2001 From: Aisha Tammy Date: Thu, 14 Dec 2023 20:49:01 -0500 Subject: [PATCH 4/7] add mutual TLS tests --- tests/test_regress_syslogng.py | 101 +++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 17 deletions(-) diff --git a/tests/test_regress_syslogng.py b/tests/test_regress_syslogng.py index 77a6e02..d1ab853 100644 --- a/tests/test_regress_syslogng.py +++ b/tests/test_regress_syslogng.py @@ -1,5 +1,6 @@ import os import socket +import ssl import subprocess from time import sleep import unittest @@ -27,7 +28,7 @@ class TestSyslogNG(TestCertManager): - def _start_server(self, ip): + def _start_server(self): # create syslog-ng tls config config = """ @version: 4.4 @@ -102,6 +103,7 @@ def _start_server(self, ip): tls( key-file("{0}/syslog.key") cert-file("{0}/syslog.pub") + ca-file("{0}/syslog.pub") peer-verify(required-trusted) ) ); @@ -115,6 +117,7 @@ def _start_server(self, ip): tls( key-file("{0}/syslog.key") cert-file("{0}/syslog.pub") + ca-file("{0}/syslog.pub") peer-verify(required-trusted) ) ); @@ -230,8 +233,8 @@ def _stop_server(self): self.server_pid.kill() self.server_pid.wait() - def test_syslogng_inet_DGRAM(self): - self._start_server("127.0.0.1") + def test_SYSLOGNG_INET4_DGRAM(self): + self._start_server() test_logger = self._build_logger() @@ -252,8 +255,8 @@ def test_syslogng_inet_DGRAM(self): finally: self._stop_server() - def test_syslogng_inet_STREAM(self): - self._start_server("127.0.0.1") + def test_SYSLOGNG_INET4_STREAM(self): + self._start_server() test_logger = self._build_logger() @@ -274,8 +277,8 @@ def test_syslogng_inet_STREAM(self): finally: self._stop_server() - def test_syslogng_inet_TLS(self): - self._start_server("127.0.0.1") + def test_SYSLOGNG_INET4_TLS(self): + self._start_server() test_logger = self._build_logger() @@ -298,8 +301,8 @@ def test_syslogng_inet_TLS(self): finally: self._stop_server() - def test_syslogng_unix_DGRAM(self): - self._start_server("127.0.0.1") + def test_SYSLOGNG_unix_DGRAM(self): + self._start_server() test_logger = self._build_logger() @@ -320,8 +323,8 @@ def test_syslogng_unix_DGRAM(self): finally: self._stop_server() - def test_syslogng_unix_STREAM(self): - self._start_server("127.0.0.1") + def test_SYSLOGNG_unix_STREAM(self): + self._start_server() test_logger = self._build_logger() @@ -343,8 +346,8 @@ def test_syslogng_unix_STREAM(self): finally: self._stop_server() - def test_syslogng_inet6_DGRAM(self): - self._start_server("::1") + def test_SYSLOGNG_INET6_DGRAM(self): + self._start_server() test_logger = self._build_logger() @@ -365,8 +368,8 @@ def test_syslogng_inet6_DGRAM(self): finally: self._stop_server() - def test_syslogng_inet6_STREAM(self): - self._start_server("::1") + def test_SYSLOGNG_INET6_STREAM(self): + self._start_server() test_logger = self._build_logger() @@ -387,8 +390,8 @@ def test_syslogng_inet6_STREAM(self): finally: self._stop_server() - def test_syslogng_inet6_TLS(self): - self._start_server("::1") + def test_SYSLOGNG_INET6_TLS(self): + self._start_server() test_logger = self._build_logger() @@ -410,3 +413,67 @@ def test_syslogng_inet6_TLS(self): self.assertTrue(uuid_message in data) finally: self._stop_server() + + def test_SYSLOGNG_INET4_MUTUAL_TLS(self): + self._start_server() + + test_logger = self._build_logger() + + # custom context for mutual TLS + context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context.load_cert_chain( + certfile=self.tmpdir.name + "/syslog.pub", + keyfile=self.tmpdir.name + "/syslog.key", + ) + context.load_verify_locations(cafile=self.tmpdir.name + "/syslog.pub") + + handler = TLSSysLogHandler( + address=("127.0.0.1", SOCKET_PORT4_MUTUAL_TLS), + socktype=socket.SOCK_STREAM, + secure=context, + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() + + def test_SYSLOGNG_INET6_MUTUAL_TLS(self): + self._start_server() + + test_logger = self._build_logger() + + # custom context for mutual TLS + context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context.load_cert_chain( + certfile=self.tmpdir.name + "/syslog.pub", + keyfile=self.tmpdir.name + "/syslog.key", + ) + context.load_verify_locations(cafile=self.tmpdir.name + "/syslog.pub") + + handler = TLSSysLogHandler( + address=("::1", SOCKET_PORT6_MUTUAL_TLS), + socktype=socket.SOCK_STREAM, + secure=context, + ) + test_logger.addHandler(handler) + + uuid_message = uuid.uuid4().hex + test_logger.critical(uuid_message) + + sleep(2) + + try: + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) + finally: + self._stop_server() From 88b7684caa4760fac5b3dcc28a575a3eae35c450 Mon Sep 17 00:00:00 2001 From: Aisha Tammy Date: Thu, 14 Dec 2023 20:56:04 -0500 Subject: [PATCH 5/7] mutual tls example --- README.rst | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 1bdfd7a..b4613b7 100644 --- a/README.rst +++ b/README.rst @@ -36,17 +36,22 @@ Usage secure={cafile='/path/to/ca/file'}) logger.addHandler(handler2) - # with custom SSLContext - context = ssl.create_default_context(cafile='/path/to/ca/file') + # with custom SSLContext (e.g. for mutual TLS authentication) + context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context.load_cert_chain( + certfile="/path/to/client/cert.pem", + keyfile="/path/to/client/priv.key", + ) + context.load_verify_locations(cafile="/path/to/ca/file") handler3 = TLSSysLogHandler(address=('secure-logging.example.com', 6514), socktype=socket.SOCK_STREAM, secure=context) logger.addHandler(handler3) - # or allow TLS without verification + # or allow TLS without verification (not recommended) handler4 = TLSSysLogHandler(address=('secure-logging.example.com', 6514), socktype=socket.SOCK_STREAM, secure="noverify") logger.addHandler(handler4) - logger.info('Hello World!') + logger.info('Hello, World!') From 666a36e43d3759fcb27e8600a731c09e4272e667 Mon Sep 17 00:00:00 2001 From: Aisha Tammy Date: Thu, 14 Dec 2023 22:05:17 -0500 Subject: [PATCH 6/7] move start/stop_server to setUp/tearDown --- tests/test_regress_syslogng.py | 116 +++++++++++---------------------- 1 file changed, 37 insertions(+), 79 deletions(-) diff --git a/tests/test_regress_syslogng.py b/tests/test_regress_syslogng.py index d1ab853..4eca6b8 100644 --- a/tests/test_regress_syslogng.py +++ b/tests/test_regress_syslogng.py @@ -233,9 +233,15 @@ def _stop_server(self): self.server_pid.kill() self.server_pid.wait() - def test_SYSLOGNG_INET4_DGRAM(self): + def setUp(self): + super().setUp() self._start_server() + def tearDown(self): + self._stop_server() + super().tearDown() + + def test_SYSLOGNG_INET4_DGRAM(self): test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -248,16 +254,11 @@ def test_SYSLOGNG_INET4_DGRAM(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_INET4_STREAM(self): - self._start_server() - test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -270,16 +271,11 @@ def test_SYSLOGNG_INET4_STREAM(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_INET4_TLS(self): - self._start_server() - test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -294,16 +290,11 @@ def test_SYSLOGNG_INET4_TLS(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_unix_DGRAM(self): - self._start_server() - test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -316,16 +307,11 @@ def test_SYSLOGNG_unix_DGRAM(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_unix_STREAM(self): - self._start_server() - test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -339,16 +325,11 @@ def test_SYSLOGNG_unix_STREAM(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_INET6_DGRAM(self): - self._start_server() - test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -361,16 +342,11 @@ def test_SYSLOGNG_INET6_DGRAM(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_INET6_STREAM(self): - self._start_server() - test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -383,16 +359,11 @@ def test_SYSLOGNG_INET6_STREAM(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_INET6_TLS(self): - self._start_server() - test_logger = self._build_logger() handler = TLSSysLogHandler( @@ -407,16 +378,11 @@ def test_SYSLOGNG_INET6_TLS(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_INET4_MUTUAL_TLS(self): - self._start_server() - test_logger = self._build_logger() # custom context for mutual TLS @@ -439,16 +405,11 @@ def test_SYSLOGNG_INET4_MUTUAL_TLS(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) def test_SYSLOGNG_INET6_MUTUAL_TLS(self): - self._start_server() - test_logger = self._build_logger() # custom context for mutual TLS @@ -471,9 +432,6 @@ def test_SYSLOGNG_INET6_MUTUAL_TLS(self): sleep(2) - try: - with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: - data = f.read() - self.assertTrue(uuid_message in data) - finally: - self._stop_server() + with open(os.path.join(self.tmpdir.name, "syslog.log")) as f: + data = f.read() + self.assertTrue(uuid_message in data) From fdb908ebfe2a73b2ec3c7152a38480fe7c9dd240 Mon Sep 17 00:00:00 2001 From: Aisha Tammy Date: Thu, 14 Dec 2023 22:09:05 -0500 Subject: [PATCH 7/7] use create_default_context for mutual auth --- README.rst | 5 +++-- tests/test_regress_syslogng.py | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index b4613b7..fae7635 100644 --- a/README.rst +++ b/README.rst @@ -37,12 +37,13 @@ Usage logger.addHandler(handler2) # with custom SSLContext (e.g. for mutual TLS authentication) - context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context = ssl.create_default_context( + purpose=ssl.Purpose.SERVER_AUTH, cafile="/path/to/ca/file" + ) context.load_cert_chain( certfile="/path/to/client/cert.pem", keyfile="/path/to/client/priv.key", ) - context.load_verify_locations(cafile="/path/to/ca/file") handler3 = TLSSysLogHandler(address=('secure-logging.example.com', 6514), socktype=socket.SOCK_STREAM, secure=context) diff --git a/tests/test_regress_syslogng.py b/tests/test_regress_syslogng.py index 4eca6b8..0ebe187 100644 --- a/tests/test_regress_syslogng.py +++ b/tests/test_regress_syslogng.py @@ -386,12 +386,13 @@ def test_SYSLOGNG_INET4_MUTUAL_TLS(self): test_logger = self._build_logger() # custom context for mutual TLS - context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context = ssl.create_default_context( + purpose=ssl.Purpose.SERVER_AUTH, cafile=self.tmpdir.name + "/syslog.pub" + ) context.load_cert_chain( certfile=self.tmpdir.name + "/syslog.pub", keyfile=self.tmpdir.name + "/syslog.key", ) - context.load_verify_locations(cafile=self.tmpdir.name + "/syslog.pub") handler = TLSSysLogHandler( address=("127.0.0.1", SOCKET_PORT4_MUTUAL_TLS), @@ -413,12 +414,13 @@ def test_SYSLOGNG_INET6_MUTUAL_TLS(self): test_logger = self._build_logger() # custom context for mutual TLS - context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context = ssl.create_default_context( + purpose=ssl.Purpose.SERVER_AUTH, cafile=self.tmpdir.name + "/syslog.pub" + ) context.load_cert_chain( certfile=self.tmpdir.name + "/syslog.pub", keyfile=self.tmpdir.name + "/syslog.key", ) - context.load_verify_locations(cafile=self.tmpdir.name + "/syslog.pub") handler = TLSSysLogHandler( address=("::1", SOCKET_PORT6_MUTUAL_TLS),