24
24
import socket
25
25
import struct
26
26
import re
27
+ import functools
27
28
28
29
# For python 2 and 3 compatibility
29
30
try :
@@ -187,11 +188,25 @@ def __init__(self,
187
188
self .chunk_size = chunk_size
188
189
self .timeout = timeout
189
190
190
- self .socket_wrapper = socket_wrapper
191
191
if use_config :
192
192
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
+ )
193
205
else :
194
206
self .zabbix_uri = [(zabbix_server , zabbix_port )]
207
+ self .psk_identity = None
208
+ self .psk_file = None
209
+ self .socket_wrapper = socket_wrapper
195
210
196
211
def __repr__ (self ):
197
212
"""Represent detailed ZabbixSender view."""
@@ -201,7 +216,7 @@ def __repr__(self):
201
216
202
217
return result
203
218
204
- def _load_from_config (self , config_file ):
219
+ def _load_from_config (self , config_file , return_param = 'ServerActive' ):
205
220
"""Load zabbix server IP address and port from zabbix agent config
206
221
file.
207
222
@@ -240,22 +255,28 @@ def _load_from_config(self, config_file):
240
255
config_file_fp = StringIO (config_file_data )
241
256
config = configparser .RawConfigParser (** params )
242
257
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'
250
258
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 )
259
280
260
281
return result
261
282
@@ -442,3 +463,36 @@ def send(self, metrics):
442
463
for m in range (0 , len (metrics ), self .chunk_size ):
443
464
result .parse (self ._chunk_send (metrics [m :m + self .chunk_size ]))
444
465
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