Skip to content

Commit f028d33

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

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,9 @@
2424
import socket
2525
import struct
2626
import re
27+
import functools
28+
import ssl
29+
import sslpsk
2730

2831
# For python 2 and 3 compatibility
2932
try:
@@ -187,11 +190,25 @@ def __init__(self,
187190
self.chunk_size = chunk_size
188191
self.timeout = timeout
189192

190-
self.socket_wrapper = socket_wrapper
191193
if use_config:
192194
self.zabbix_uri = self._load_from_config(use_config)
195+
psk_identity = self._load_from_config(use_config,'TLSPSKIdentity')
196+
psk_file = self._load_from_config(use_config,'TLSPSKFile')
197+
if psk_identity and psk_file:
198+
with open(psk_file, "r") as psk_data:
199+
psk_txt = psk_data.readlines()[0]
200+
self.socket_wrapper = functools.partial(
201+
PyZabbixPSKSocketWrapper,
202+
identity=psk_identity, # your PSK identity
203+
psk=bytes.fromhex(
204+
psk_txt # your PSK
205+
)
206+
)
193207
else:
194208
self.zabbix_uri = [(zabbix_server, zabbix_port)]
209+
self.psk_identity = None
210+
self.psk_file = None
211+
self.socket_wrapper = socket_wrapper
195212

196213
def __repr__(self):
197214
"""Represent detailed ZabbixSender view."""
@@ -201,7 +218,7 @@ def __repr__(self):
201218

202219
return result
203220

204-
def _load_from_config(self, config_file):
221+
def _load_from_config(self, config_file, return_param='ServerActive'):
205222
"""Load zabbix server IP address and port from zabbix agent config
206223
file.
207224
@@ -240,22 +257,28 @@ def _load_from_config(self, config_file):
240257
config_file_fp = StringIO(config_file_data)
241258
config = configparser.RawConfigParser(**params)
242259
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'
250260

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)
261+
result = ''
262+
if return_param == 'ServerActive':
263+
# Prefer ServerActive, then try Server and fallback to defaults
264+
if config.has_option('root', 'ServerActive'):
265+
zabbix_serveractives = config.get('root', 'ServerActive')
266+
elif config.has_option('root', 'Server'):
267+
zabbix_serveractives = config.get('root', 'Server')
268+
else:
269+
zabbix_serveractives = '127.0.0.1:10051'
270+
271+
result = []
272+
for serverport in zabbix_serveractives.split(','):
273+
if ':' not in serverport:
274+
serverport = "%s:%s" % (serverport.strip(), 10051)
275+
server, port = serverport.split(':')
276+
serverport = (server, int(port))
277+
result.append(serverport)
278+
logger.debug("Loaded params: %s", result)
279+
else:
280+
if config.has_option('root', return_param):
281+
result = config.get('root', return_param)
259282

260283
return result
261284

@@ -442,3 +465,34 @@ def send(self, metrics):
442465
for m in range(0, len(metrics), self.chunk_size):
443466
result.parse(self._chunk_send(metrics[m:m + self.chunk_size]))
444467
return result
468+
469+
470+
class PyZabbixPSKSocketWrapper:
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)