From 3a7b880bdf70d295ed8af3a5880bab65fa6b3932 Mon Sep 17 00:00:00 2001 From: Peter Hamilton Date: Tue, 24 Apr 2018 21:57:20 -0400 Subject: [PATCH] Fix a denial-of-service bug by setting the server socket timeout This change fixes a potential denial-of-service bug with the server, setting a default timeout for all server sockets. This allows the server to drop hung connections without blocking forever. The interrupt triggered during accept calls is expected and is now handled appropriately. Server unit tests have been updated to reflect this change. Closes #430 --- kmip/services/server/server.py | 6 ++++++ kmip/tests/unit/services/server/test_server.py | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/kmip/services/server/server.py b/kmip/services/server/server.py index 6c0622e..eaa33fd 100644 --- a/kmip/services/server/server.py +++ b/kmip/services/server/server.py @@ -267,6 +267,7 @@ class KmipServer(object): self._logger.info("Starting server socket handler.") # Create a TCP stream socket and configure it for immediate reuse. + socket.setdefaulttimeout(10) self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) @@ -407,6 +408,11 @@ class KmipServer(object): while self._is_serving: try: connection, address = self._socket.accept() + except socket.timeout: + # Setting the default socket timeout to break hung connections + # will cause accept to periodically raise socket.timeout. This + # is expected behavior, so ignore it and retry accept. + pass except socket.error as e: self._logger.warning( "Error detected while establishing new connection." diff --git a/kmip/tests/unit/services/server/test_server.py b/kmip/tests/unit/services/server/test_server.py index d450e09..e228747 100644 --- a/kmip/tests/unit/services/server/test_server.py +++ b/kmip/tests/unit/services/server/test_server.py @@ -485,7 +485,11 @@ class TestKmipServer(testtools.TestCase): # Test the expected behavior for a normal server/interrupt sequence s._socket.accept = mock.MagicMock( - side_effect=[('connection', 'address'), expected_error] + side_effect=[ + ('connection', 'address'), + socket.timeout, + expected_error + ] ) s.serve()