Skip to content

Commit 18f546d

Browse files
author
dmitry.duka
committed
fix for #114
1 parent 8d2b855 commit 18f546d

File tree

1 file changed

+71
-17
lines changed

1 file changed

+71
-17
lines changed

pyzabbix/sender.py

+71-17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import socket
2525
import struct
2626
import re
27+
import functools
2728

2829
# For python 2 and 3 compatibility
2930
try:
@@ -187,11 +188,25 @@ def __init__(self,
187188
self.chunk_size = chunk_size
188189
self.timeout = timeout
189190

190-
self.socket_wrapper = socket_wrapper
191191
if use_config:
192192
self.zabbix_uri = self._load_from_config(use_config)
193+
psk_identity = self._load_from_config(use_config,'TLSPSKIdentity')
194+
psk_file = self._load_from_config(use_config,'TLSPSKFile')
195+
if psk_identity and psk_file:
196+
with open(psk_file, "r") as psk_data:
197+
psk_txt = psk_data.readlines()[0]
198+
self.socket_wrapper = functools.partial(
199+
PyZabbixPSKSocketWrapper,
200+
identity=psk_identity, # your PSK identity
201+
psk=bytes.fromhex(
202+
psk_txt # your PSK
203+
)
204+
)
193205
else:
194206
self.zabbix_uri = [(zabbix_server, zabbix_port)]
207+
self.psk_identity = None
208+
self.psk_file = None
209+
self.socket_wrapper = socket_wrapper
195210

196211
def __repr__(self):
197212
"""Represent detailed ZabbixSender view."""
@@ -201,7 +216,7 @@ def __repr__(self):
201216

202217
return result
203218

204-
def _load_from_config(self, config_file):
219+
def _load_from_config(self, config_file, return_param='ServerActive'):
205220
"""Load zabbix server IP address and port from zabbix agent config
206221
file.
207222
@@ -240,22 +255,28 @@ def _load_from_config(self, config_file):
240255
config_file_fp = StringIO(config_file_data)
241256
config = configparser.RawConfigParser(**params)
242257
config.readfp(config_file_fp)
243-
# Prefer ServerActive, then try Server and fallback to defaults
244-
if config.has_option('root', 'ServerActive'):
245-
zabbix_serveractives = config.get('root', 'ServerActive')
246-
elif config.has_option('root', 'Server'):
247-
zabbix_serveractives = config.get('root', 'Server')
248-
else:
249-
zabbix_serveractives = '127.0.0.1:10051'
250258

251-
result = []
252-
for serverport in zabbix_serveractives.split(','):
253-
if ':' not in serverport:
254-
serverport = "%s:%s" % (serverport.strip(), 10051)
255-
server, port = serverport.split(':')
256-
serverport = (server, int(port))
257-
result.append(serverport)
258-
logger.debug("Loaded params: %s", result)
259+
result = ''
260+
if return_param == 'ServerActive':
261+
# Prefer ServerActive, then try Server and fallback to defaults
262+
if config.has_option('root', 'ServerActive'):
263+
zabbix_serveractives = config.get('root', 'ServerActive')
264+
elif config.has_option('root', 'Server'):
265+
zabbix_serveractives = config.get('root', 'Server')
266+
else:
267+
zabbix_serveractives = '127.0.0.1:10051'
268+
269+
result = []
270+
for serverport in zabbix_serveractives.split(','):
271+
if ':' not in serverport:
272+
serverport = "%s:%s" % (serverport.strip(), 10051)
273+
server, port = serverport.split(':')
274+
serverport = (server, int(port))
275+
result.append(serverport)
276+
logger.debug("Loaded params: %s", result)
277+
else:
278+
if config.has_option('root', return_param):
279+
result = config.get('root', return_param)
259280

260281
return result
261282

@@ -442,3 +463,36 @@ def send(self, metrics):
442463
for m in range(0, len(metrics), self.chunk_size):
443464
result.parse(self._chunk_send(metrics[m:m + self.chunk_size]))
444465
return result
466+
467+
468+
class PyZabbixPSKSocketWrapper:
469+
import ssl
470+
import sslpsk
471+
"""Implements ssl.wrap_socket with PSK instead of certificates.
472+
473+
Proxies calls to a `socket` instance.
474+
"""
475+
476+
def __init__(self, sock, *, identity, psk):
477+
self.__sock = sock
478+
self.__identity = identity
479+
self.__psk = psk
480+
481+
def connect(self, *args, **kwargs):
482+
# `sslpsk.wrap_socket` must be called *after* socket.connect,
483+
# while the `ssl.wrap_socket` must be called *before* socket.connect.
484+
self.__sock.connect(*args, **kwargs)
485+
486+
# `sslv3 alert bad record mac` exception means incorrect PSK
487+
self.__sock = sslpsk.wrap_socket(
488+
self.__sock,
489+
# https://github.com/zabbix/zabbix/blob/f0a1ad397e5653238638cd1a65a25ff78c6809bb/src/libs/zbxcrypto/tls.c#L3231
490+
ssl_version=ssl.PROTOCOL_TLSv1_2,
491+
# https://github.com/zabbix/zabbix/blob/f0a1ad397e5653238638cd1a65a25ff78c6809bb/src/libs/zbxcrypto/tls.c#L3179
492+
ciphers="PSK-AES128-CBC-SHA",
493+
psk=(self.__psk, self.__identity),
494+
)
495+
496+
def __getattr__(self, name):
497+
return getattr(self.__sock, name)
498+

0 commit comments

Comments
 (0)