Fix: apistatusd.py

- Changed apistatusd.conf: set server.host default value to 0.0.0.0 to
  improve error messages; needs checking if this disabled ipv6
- Changed apistatusd.conf: renamed default client.cert filename to
  improve meaning

- Fix create_ssl_context: context.options was reset by misuse of `=`
  instead of binary or assignment `|=`
- Changed main/socket-creation: disabled keepalive
- Fix main/connection/pre-ssl-handshake: set missing tls handshake
  timeout; code went into infinite waiting block
- Some cleanup
This commit is contained in:
Ludwig Behm 2023-10-23 23:50:29 +02:00
parent 26e6ae6374
commit d9cf4695b8
Signed by: l.behm
GPG key ID: D344835D63B89384
2 changed files with 20 additions and 15 deletions

View file

@ -12,14 +12,14 @@ timeout = 5.0
loglevel = debug loglevel = debug
[server] [server]
host = localhost host = 0.0.0.0
port = 10001 port = 10001
cert = ./certs/statusd-pub.pem cert = ./certs/statusd-pub.pem
key = ./certs/statusd-key.pem key = ./certs/statusd-key.pem
[client] [client]
cert = ./certs/statusclient-pub.pem cert = ./certs/client-ca.pem
# possible values: true, false, may # possible values: false, may, true
required = true required = true
[api] [api]

View file

@ -56,23 +56,25 @@ def create_ssl_context(config):
return: context object or None return: context object or None
''' '''
context = None context = None
requirement = None requirement = ssl.CERT_REQUIRED
required = config['client']['required'].lower() required = config['client']['required'].lower()
if required == 'false': if required == 'false':
requirement = ssl.CERT_NONE requirement = ssl.CERT_NONE
elif required == 'may': elif required == 'may':
requirement = ssl.CERT_OPTIONAL requirement = ssl.CERT_OPTIONAL
else: requirement = ssl.CERT_REQUIRED
try: try:
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.verify_mode = requirement context.verify_mode = requirement
context.load_cert_chain(certfile=config['server']['cert'], context.load_cert_chain(certfile=config['server']['cert'],
keyfile=config['server']['key']) keyfile=config['server']['key'])
context.load_verify_locations(cafile=config['client']['cert']) context.load_verify_locations(cafile=config['client']['cert'])
#context.minimum_version = ssl.TLSVersion.TLSv1_2
#context.maximum_version = ssl.TLSVersion.TLSv1_2
# ensure, compression is disabled (disabled by default anyway at the moment) # ensure, compression is disabled (disabled by default anyway at the moment)
context.options |= ssl.OP_NO_COMPRESSION context.options |= ssl.OP_NO_COMPRESSION
context.options = ssl.PROTOCOL_TLS_SERVER context.options |= ssl.OP_CIPHER_SERVER_PREFERENCE
context.options = ssl.OP_CIPHER_SERVER_PREFERENCE
logging.debug('SSL context created') logging.debug('SSL context created')
except Exception as e: except Exception as e:
logging.error('Failed to create SSL context') logging.error('Failed to create SSL context')
@ -101,7 +103,7 @@ def print_context(ctx):
logging.debug('Minimum version ssl: {}'.format(ctx.minimum_version)) logging.debug('Minimum version ssl: {}'.format(ctx.minimum_version))
logging.debug('Maximum version ssl: {}'.format(ctx.maximum_version)) logging.debug('Maximum version ssl: {}'.format(ctx.maximum_version))
logging.debug('SSL options enabled: {}'.format(ctx.options)) logging.debug('SSL options enabled: {}'.format(ctx.options))
logging.debug('Protocol: {}'.format(ctx.protocol)) logging.debug('Protocol: {}'.format(ssl.get_protocol_name(ctx.protocol)))
logging.debug('Verify flags certificates: {}'.format(ctx.verify_flags)) logging.debug('Verify flags certificates: {}'.format(ctx.verify_flags))
logging.debug('Verify mode: {}'.format(ctx.verify_mode)) logging.debug('Verify mode: {}'.format(ctx.verify_mode))
print_ciphers(ctx.get_ciphers()) print_ciphers(ctx.get_ciphers())
@ -415,18 +417,18 @@ def main():
# ssl context erstellen # ssl context erstellen
context = create_ssl_context(config) context = create_ssl_context(config)
if context is not None: if context is None:
sys.exit(2)
print_context(context) print_context(context)
else: sys.exit(2)
try: try:
# tcp socket öffnen => MySocket # tcp socket öffnen => MySocket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as MySocket: with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as MySocket:
logging.debug('TCP Socket created') logging.debug('TCP Socket created')
MySocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) MySocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
MySocket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # MySocket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
keep = MySocket.getsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE) # keep = MySocket.getsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE)
logging.debug('Socket keepalive: {}'.format(keep)) # logging.debug('Socket keepalive: {}'.format(keep))
try: try:
MySocket.bind((config['server']['host'], int(config['server']['port']))) MySocket.bind((config['server']['host'], int(config['server']['port'])))
MySocket.listen(5) MySocket.listen(5)
@ -442,6 +444,8 @@ def main():
logging.info('Client connected: {}:{}'.format(ClientAddress[0], ClientAddress[1])) logging.info('Client connected: {}:{}'.format(ClientAddress[0], ClientAddress[1]))
# die verbindung in den ssl-context verpacken => Connection # die verbindung in den ssl-context verpacken => Connection
try: try:
ClientSocket.settimeout(float(config['general']['timeout']))
logging.debug('set ssl handshake timeout to {}s'.format(ClientSocket.gettimeout()))
Connection = context.wrap_socket(ClientSocket, server_side=True) Connection = context.wrap_socket(ClientSocket, server_side=True)
logging.info('SSL Connection established') logging.info('SSL Connection established')
Connection.settimeout(float(config['general']['timeout'])) Connection.settimeout(float(config['general']['timeout']))
@ -466,7 +470,8 @@ def main():
logging.error('InitException: {}'.format(e)) logging.error('InitException: {}'.format(e))
except Exception as ex: except Exception as ex:
logging.debug('Exception: {}'.format(ex)) logging.debug('Exception: {}'.format(ex))
else: logging.debug('Toot is set to false') else:
logging.debug('Toot is set to false')
logging.debug('Send {} back'.format(raw_data)) logging.debug('Send {} back'.format(raw_data))
Connection.send(answer) Connection.send(answer)
Connection.close() Connection.close()