Skip to content

Commit

Permalink
Fix race in stunnel port selection
Browse files Browse the repository at this point in the history
  • Loading branch information
tsmetana committed Apr 25, 2022
1 parent 443476f commit 1bbe91b
Showing 1 changed file with 19 additions and 12 deletions.
31 changes: 19 additions & 12 deletions src/mount_efs/__init__.py
Expand Up @@ -923,7 +923,7 @@ def get_tls_port_range(config):
return lower_bound, upper_bound


def choose_tls_port(config, options):
def choose_tls_port(state_file_dir, fs_id, mountpoint, config, options):
if "tlsport" in options:
ports_to_try = [int(options["tlsport"])]
else:
Expand All @@ -938,13 +938,13 @@ def choose_tls_port(config, options):
assert len(tls_ports) == len(ports_to_try)

if "netns" not in options:
tls_port = find_tls_port_in_range(ports_to_try)
sock = find_tls_port_in_range(state_file_dir, fs_id, mountpoint, ports_to_try)
else:
with NetNS(nspath=options["netns"]):
tls_port = find_tls_port_in_range(ports_to_try)
sock = find_tls_port_in_range(state_file_dir, fs_id, mountpoint, ports_to_try)

if tls_port:
return tls_port
if sock:
return sock

if "tlsport" in options:
fatal_error(
Expand All @@ -958,14 +958,18 @@ def choose_tls_port(config, options):
)


def find_tls_port_in_range(ports_to_try):
def find_tls_port_in_range(state_file_dir, fs_id, mountpoint, ports_to_try):
sock = socket.socket()
for tls_port in ports_to_try:
mount_filename = get_mount_specific_filename(fs_id, mountpoint, tls_port)
config_file = get_stunnel_config_filename(state_file_dir, mount_filename)
if os.access(config_file, os.R_OK):
logging.info("confifguration for port %s already exists, trying another port", tls_port)
continue
try:
logging.info("binding %s", tls_port)
sock.bind(("localhost", tls_port))
sock.close()
return tls_port
return sock
except socket.error as e:
logging.info(e)
continue
Expand Down Expand Up @@ -1210,9 +1214,7 @@ def write_stunnel_config_file(
)
logging.debug("Writing stunnel configuration:\n%s", stunnel_config)

stunnel_config_file = os.path.join(
state_file_dir, "stunnel-config.%s" % mount_filename
)
stunnel_config_file = get_stunnel_config_filename(state_file_dir, mount_filename)

with open(stunnel_config_file, "w") as f:
f.write(stunnel_config)
Expand Down Expand Up @@ -1409,6 +1411,8 @@ def create_required_directory(config, directory):
if errno.EEXIST != e.errno or not os.path.isdir(directory):
raise

def get_stunnel_config_filename(state_file_dir, mount_filename):
return os.path.join(state_file_dir, "stunnel-config.%s" % mount_filename)

@contextmanager
def bootstrap_tls(
Expand All @@ -1421,7 +1425,8 @@ def bootstrap_tls(
state_file_dir=STATE_FILE_DIR,
fallback_ip_address=None,
):
tls_port = choose_tls_port(config, options)
sock = choose_tls_port(state_file_dir, fs_id, mountpoint, config, options)
tls_port = sock.getsockname()[1]
# override the tlsport option so that we can later override the port the NFS client uses to connect to stunnel.
# if the user has specified tlsport=X at the command line this will just re-set tlsport to X.
options["tlsport"] = tls_port
Expand Down Expand Up @@ -1497,6 +1502,8 @@ def bootstrap_tls(
cert_details=cert_details,
fallback_ip_address=fallback_ip_address,
)
# close the socket now, so the stunnel process can bind to the port
sock.close()
tunnel_args = [_stunnel_bin(), stunnel_config_file]
if "netns" in options:
tunnel_args = ["nsenter", "--net=" + options["netns"]] + tunnel_args
Expand Down

0 comments on commit 1bbe91b

Please sign in to comment.