From e11e42f98e37fdaed8eb15fe33ef8d83f1c3bcc8 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Tue, 12 Jul 2016 15:09:31 +0300 Subject: [PATCH] Added simple socket bind check for populated ports if psutil is not available --- certbot/plugins/util.py | 64 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/certbot/plugins/util.py b/certbot/plugins/util.py index 5fc98dff6..0ee2b1587 100644 --- a/certbot/plugins/util.py +++ b/certbot/plugins/util.py @@ -2,14 +2,25 @@ import logging import socket -import psutil import zope.component from certbot import interfaces +try: + import psutil + USE_PSUTIL = True +except ImportError: + USE_PSUTIL = False logger = logging.getLogger(__name__) +RENEWER_EXTRA_MSG = ( + " For automated renewal, you may want to use a script that stops" + " and starts your webserver. You can find an example at" + " https://letsencrypt.org/howitworks/#writing-your-own-renewal-script" + ". Alternatively you can use the webroot plugin to renew without" + " needing to stop and start your webserver.") + def already_listening(port, renewer=False): """Check if a process is already listening on the port. @@ -23,6 +34,50 @@ def already_listening(port, renewer=False): :param int port: The TCP port in question. :returns: True or False. + """ + + if USE_PSUTIL: + return already_listening_psutil(port, renewer=renewer) + else: + logger.debug("Psutil not found, using simple socket check.") + return already_listening_socket(port, renewer=renewer) + + +def already_listening_socket(port, renewer=False): + """Simple socket based check to find out if port is already in use + + :param int port: The TCP port in question. + :returns: True or False + """ + + try: + testsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + try: + testsocket.bind(("", port)) + except socket.error: + display = zope.component.getUtility(interfaces.IDisplay) + extra = "" + if renewer: + extra = RENEWER_EXTRA_MSG + display.notification( + "Port {0} is already in use by another process. This will " + "prevent us from binding to that port. Please stop the " + "process that is populating the port in question and try " + "again. {1}".format(port, extra), height=13) + return True + finally: + testsocket.close() + except socket.error: + pass + return False + + +def already_listening_psutil(port, renewer=False): + """Psutil variant of the open port check + + :param int port: The TCP port in question. + :returns: True or False. + """ try: net_connections = psutil.net_connections() @@ -51,12 +106,7 @@ def already_listening(port, renewer=False): display = zope.component.getUtility(interfaces.IDisplay) extra = "" if renewer: - extra = ( - " For automated renewal, you may want to use a script that stops" - " and starts your webserver. You can find an example at" - " https://letsencrypt.org/howitworks/#writing-your-own-renewal-script" - ". Alternatively you can use the webroot plugin to renew without" - " needing to stop and start your webserver.") + extra = RENEWER_EXTRA_MSG display.notification( "The program {0} (process ID {1}) is already listening " "on TCP port {2}. This will prevent us from binding to "