Skip to content

Commit

Permalink
fix for adubkov#114
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitry.duka committed Jan 29, 2021
1 parent 8d2b855 commit 19414cd
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 17 deletions.
88 changes: 71 additions & 17 deletions pyzabbix/sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import socket
import struct
import re
import functools
import ssl
import sslpsk

# For python 2 and 3 compatibility
try:
Expand Down Expand Up @@ -187,11 +190,25 @@ def __init__(self,
self.chunk_size = chunk_size
self.timeout = timeout

self.socket_wrapper = socket_wrapper
if use_config:
self.zabbix_uri = self._load_from_config(use_config)
psk_identity = self._load_from_config(use_config,'TLSPSKIdentity')
psk_file = self._load_from_config(use_config,'TLSPSKFile')
if psk_identity and psk_file:
with open(psk_file, "r") as psk_data:
psk_txt = psk_data.readlines()[0]
self.socket_wrapper = functools.partial(
PyZabbixPSKSocketWrapper,
identity=psk_identity, # your PSK identity
psk=bytes.fromhex(
psk_txt # your PSK
)
)
else:
self.zabbix_uri = [(zabbix_server, zabbix_port)]
self.psk_identity = None
self.psk_file = None
self.socket_wrapper = socket_wrapper

def __repr__(self):
"""Represent detailed ZabbixSender view."""
Expand All @@ -201,7 +218,7 @@ def __repr__(self):

return result

def _load_from_config(self, config_file):
def _load_from_config(self, config_file, return_param='ServerActive'):
"""Load zabbix server IP address and port from zabbix agent config
file.
Expand Down Expand Up @@ -240,22 +257,28 @@ def _load_from_config(self, config_file):
config_file_fp = StringIO(config_file_data)
config = configparser.RawConfigParser(**params)
config.readfp(config_file_fp)
# Prefer ServerActive, then try Server and fallback to defaults
if config.has_option('root', 'ServerActive'):
zabbix_serveractives = config.get('root', 'ServerActive')
elif config.has_option('root', 'Server'):
zabbix_serveractives = config.get('root', 'Server')
else:
zabbix_serveractives = '127.0.0.1:10051'

result = []
for serverport in zabbix_serveractives.split(','):
if ':' not in serverport:
serverport = "%s:%s" % (serverport.strip(), 10051)
server, port = serverport.split(':')
serverport = (server, int(port))
result.append(serverport)
logger.debug("Loaded params: %s", result)
result = ''
if return_param == 'ServerActive':
# Prefer ServerActive, then try Server and fallback to defaults
if config.has_option('root', 'ServerActive'):
zabbix_serveractives = config.get('root', 'ServerActive')
elif config.has_option('root', 'Server'):
zabbix_serveractives = config.get('root', 'Server')
else:
zabbix_serveractives = '127.0.0.1:10051'

result = []
for serverport in zabbix_serveractives.split(','):
if ':' not in serverport:
serverport = "%s:%s" % (serverport.strip(), 10051)
server, port = serverport.split(':')
serverport = (server, int(port))
result.append(serverport)
logger.debug("Loaded params: %s", result)
else:
if config.has_option('root', return_param):
result = config.get('root', return_param)

return result

Expand Down Expand Up @@ -442,3 +465,34 @@ def send(self, metrics):
for m in range(0, len(metrics), self.chunk_size):
result.parse(self._chunk_send(metrics[m:m + self.chunk_size]))
return result


class PyZabbixPSKSocketWrapper:
"""Implements ssl.wrap_socket with PSK instead of certificates.
Proxies calls to a `socket` instance.
"""

def __init__(self, sock, *, identity, psk):
self.__sock = sock
self.__identity = identity
self.__psk = psk

def connect(self, *args, **kwargs):
# `sslpsk.wrap_socket` must be called *after* socket.connect,
# while the `ssl.wrap_socket` must be called *before* socket.connect.
self.__sock.connect(*args, **kwargs)

# `sslv3 alert bad record mac` exception means incorrect PSK
self.__sock = sslpsk.wrap_socket(
self.__sock,
# https://github.com/zabbix/zabbix/blob/f0a1ad397e5653238638cd1a65a25ff78c6809bb/src/libs/zbxcrypto/tls.c#L3231
ssl_version=ssl.PROTOCOL_TLSv1_2,
# https://github.com/zabbix/zabbix/blob/f0a1ad397e5653238638cd1a65a25ff78c6809bb/src/libs/zbxcrypto/tls.c#L3179
ciphers="PSK-AES128-CBC-SHA",
psk=(self.__psk, self.__identity),
)

def __getattr__(self, name):
return getattr(self.__sock, name)

5 changes: 5 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
from setuptools import setup
from pyzabbix.version import __version__

requires = [
'sslpsk>=1.0.0,<2.0.0',
]

setup(name='py-zabbix',
version=__version__,
description='Python module to work with zabbix.',
Expand All @@ -13,6 +17,7 @@
test_suite='tests',
packages=['pyzabbix', 'zabbix'],
tests_require=['mock'],
install_requires=requires,
classifiers=[
'Development Status :: 5 - Production/Stable',
'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
Expand Down

0 comments on commit 19414cd

Please sign in to comment.