1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-26 07:41:33 +03:00

Split out parent and child listeners into methods

This commit is contained in:
Seth Schoen
2015-02-03 15:51:37 -08:00
parent 191b0d7be4
commit 63bf55a748

View File

@@ -238,7 +238,6 @@ class StandaloneAuthenticator(object):
self.subproc_inuse = False
self.subproc_cantbind = False
self.tasks = {}
self.which = None
self.sock = None
self.connection = None
self.private_key = None
@@ -311,6 +310,109 @@ class StandaloneAuthenticator(object):
new_ctx.use_privatekey(self.private_key)
connection.set_context(new_ctx)
def do_parent_process(self, port):
"""Perform the parent process side of the TCP listener task. This
should only be called by start_listener()."""
signal.signal(signal.SIGIO, self.client_signal_handler)
signal.signal(signal.SIGUSR1, self.client_signal_handler)
signal.signal(signal.SIGUSR2, self.client_signal_handler)
display = zope.component.getUtility(interfaces.IDisplay)
start_time = time.time()
while time.time() < start_time + 5:
if self.subproc_ready:
return True
if self.subproc_inuse:
display.generic_notification(
"Could not bind TCP port {} because it is already in "
"use it is already in use by another process on this "
"system (such as a web server).".format(CONFIG.PORT))
return False
if self.subproc_cantbind:
display.generic_notification(
"Could not bind TCP port {} because you don't have "
"the appropriate permissions (for example, you "
"aren't running this program as "
"root).".format(CONFIG.PORT))
return False
time.sleep(0.1)
display.generic_notification(
"Subprocess unexpectedly timed out while trying to bind TCP "
"port {}.".format(CONFIG.PORT))
return False
def do_child_process(self, port, key):
"""Perform the child process side of the TCP listener task. This
should only be called by start_listener()."""
signal.signal(signal.SIGINT, self.subproc_signal_handler)
self.sock = socket.socket()
try:
self.sock.bind(("0.0.0.0", port))
except socket.error, error:
if error.errno == socket.errno.EACCES:
# Signal permissions denied to bind TCP port
os.kill(self.parent_pid, signal.SIGUSR2)
elif error.errno == socket.errno.EADDRINUSE:
# Signal TCP port is already in use
os.kill(self.parent_pid, signal.SIGUSR1)
else:
# XXX: How to handle unknown errors in binding?
raise error
sys.exit(1)
# XXX: We could use poll mechanism to handle simultaneous
# XXX: rather than sequential inbound TCP connections here
self.sock.listen(1)
# Signal that we've successfully bound TCP port
os.kill(self.parent_pid, signal.SIGIO)
self.private_key = OpenSSL.crypto.load_privatekey(
OpenSSL.crypto.FILETYPE_PEM, key.pem)
while True:
self.connection, _ = self.sock.accept()
# The code below uses the PyOpenSSL bindings to respond to
# the client. This may expose us to bugs and vulnerabilities
# in OpenSSL (and creates additional dependencies).
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
ctx.set_verify(OpenSSL.SSL.VERIFY_NONE, lambda: False)
pem_cert = self.tasks.values()[0]
first_cert = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, pem_cert)
ctx.use_certificate(first_cert)
ctx.use_privatekey(self.private_key)
ctx.set_cipher_list("HIGH")
ctx.set_tlsext_servername_callback(self.sni_callback)
self.ssl_conn = OpenSSL.SSL.Connection(ctx, self.connection)
self.ssl_conn.set_accept_state()
self.ssl_conn.do_handshake()
self.ssl_conn.shutdown()
self.ssl_conn.close()
# The code below uses the minimal pure Python implementation
# of TLS ClientHello, ServerHello, and Certificate messages
# (as an alternative to a full TLS implementation). It will
# not reach Finished state with a compliant TLS implementation.
#
# client_hello = self.connection.recv(65536)
# result = tls_parse_client_hello(client_hello)
# if result is None:
# print "No SNI found in ClientHello, dropping connection"
# self.connection.close()
# continue
# ciphersuite, sni = result
# if sni in self.tasks:
# pem_cert = self.tasks[sni]
# else:
# # We don't know which cert to send!
# print "Unexpected SNI value", sni
# # Choose the "first" cert and send it (but maybe we
# # should just disconnect instead?)
# pem_cert = self.tasks.values()[0]
# self.connection.send(tls_generate_server_hello(ciphersuite))
# self.connection.send(tls_generate_cert_msg(pem_cert))
# self.connection.send(tls_generate_server_hello_done())
# self.connection.close()
def start_listener(self, port, key):
"""Create a child process which will start a TCP listener on the
specified port to perform the specified DVSNI challenges.
@@ -322,106 +424,12 @@ class StandaloneAuthenticator(object):
Crypto.Random.atfork()
if fork_result:
# PARENT process (still the Let's Encrypt client process)
self.which = "parent"
self.child_pid = fork_result
signal.signal(signal.SIGIO, self.client_signal_handler)
signal.signal(signal.SIGUSR1, self.client_signal_handler)
signal.signal(signal.SIGUSR2, self.client_signal_handler)
display = zope.component.getUtility(interfaces.IDisplay)
start_time = time.time()
while time.time() < start_time + 5:
if self.subproc_ready:
return True
if self.subproc_inuse:
display.generic_notification(
"Could not bind TCP port {} because it is already in "
"use it is already in use by another process on this "
"system (such as a web server).".format(CONFIG.PORT))
return False
if self.subproc_cantbind:
display.generic_notification(
"Could not bind TCP port {} because you don't have "
"the appropriate permissions (for example, you "
"aren't running this program as "
"root).".format(CONFIG.PORT))
return False
time.sleep(0.1)
display.generic_notification(
"Subprocess unexpectedly timed out while trying to bind TCP "
"port {}.".format(CONFIG.PORT))
return False
self.do_parent_process(port)
else:
# CHILD process (the TCP listener subprocess)
self.which = "child"
self.child_pid = os.getpid()
signal.signal(signal.SIGINT, self.subproc_signal_handler)
self.sock = socket.socket()
try:
self.sock.bind(("0.0.0.0", port))
except socket.error, error:
if error.errno == socket.errno.EACCES:
# Signal permissions denied to bind TCP port
os.kill(self.parent_pid, signal.SIGUSR2)
elif error.errno == socket.errno.EADDRINUSE:
# Signal TCP port is already in use
os.kill(self.parent_pid, signal.SIGUSR1)
else:
# XXX: How to handle unknown errors in binding?
raise error
sys.exit(1)
# XXX: We could use poll mechanism to handle simultaneous
# XXX: rather than sequential inbound TCP connections here
self.sock.listen(1)
# Signal that we've successfully bound TCP port
os.kill(self.parent_pid, signal.SIGIO)
self.private_key = OpenSSL.crypto.load_privatekey(
OpenSSL.crypto.FILETYPE_PEM, key.pem)
while True:
self.connection, _ = self.sock.accept()
# The code below uses the PyOpenSSL bindings to respond to
# the client. This may expose us to bugs and vulnerabilities
# in OpenSSL (and creates additional dependencies).
ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
ctx.set_verify(OpenSSL.SSL.VERIFY_NONE, lambda: False)
pem_cert = self.tasks.values()[0]
first_cert = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM, pem_cert)
ctx.use_certificate(first_cert)
ctx.use_privatekey(self.private_key)
ctx.set_cipher_list("HIGH")
ctx.set_tlsext_servername_callback(self.sni_callback)
self.ssl_conn = OpenSSL.SSL.Connection(ctx, self.connection)
self.ssl_conn.set_accept_state()
self.ssl_conn.do_handshake()
self.ssl_conn.shutdown()
self.ssl_conn.close()
# The code below uses the minimal pure Python implementation
# of TLS ClientHello, ServerHello, and Certificate messages
# (as an alternative to a full TLS implementation). It will
# not reach Finished state with a compliant TLS implementation.
#
# client_hello = self.connection.recv(65536)
# result = tls_parse_client_hello(client_hello)
# if result is None:
# print "No SNI found in ClientHello, dropping connection"
# self.connection.close()
# continue
# ciphersuite, sni = result
# if sni in self.tasks:
# pem_cert = self.tasks[sni]
# else:
# # We don't know which cert to send!
# print "Unexpected SNI value", sni
# # Choose the "first" cert and send it (but maybe we
# # should just disconnect instead?)
# pem_cert = self.tasks.values()[0]
# self.connection.send(tls_generate_server_hello(ciphersuite))
# self.connection.send(tls_generate_cert_msg(pem_cert))
# self.connection.send(tls_generate_server_hello_done())
# self.connection.close()
self.do_child_process(port, key)
# IAuthenticator method implementations follow