From 1def53e08520cf2482bf20445f095dbe5b231c2f Mon Sep 17 00:00:00 2001 From: Nikos Atlas Date: Thu, 19 May 2022 16:41:27 +0300 Subject: [PATCH] fallback to file editing in case file is locked --- sshuttle/firewall.py | 11 +++++++++-- tests/client/test_firewall.py | 23 +++++++++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/sshuttle/firewall.py b/sshuttle/firewall.py index 9108e96..43e0fb8 100644 --- a/sshuttle/firewall.py +++ b/sshuttle/firewall.py @@ -1,4 +1,5 @@ import errno +import shutil import socket import signal import sys @@ -30,7 +31,10 @@ def rewrite_etc_hosts(hostmap, port): else: raise if old_content.strip() and not os.path.exists(BAKFILE): - os.link(HOSTSFILE, BAKFILE) + try: + os.link(HOSTSFILE, BAKFILE) + except OSError: + shutil.copyfile(HOSTSFILE, BAKFILE) tmpname = "%s.%d.tmp" % (HOSTSFILE, port) f = open(tmpname, 'w') for line in old_content.rstrip().split('\n'): @@ -47,7 +51,10 @@ def rewrite_etc_hosts(hostmap, port): else: os.chown(tmpname, 0, 0) os.chmod(tmpname, 0o600) - os.rename(tmpname, HOSTSFILE) + try: + os.rename(tmpname, HOSTSFILE) + except OSError: + shutil.move(tmpname, HOSTSFILE) def restore_etc_hosts(hostmap, port): diff --git a/tests/client/test_firewall.py b/tests/client/test_firewall.py index 76aac89..7404328 100644 --- a/tests/client/test_firewall.py +++ b/tests/client/test_firewall.py @@ -1,7 +1,11 @@ import io +import os from socket import AF_INET, AF_INET6 from unittest.mock import Mock, patch, call + +import pytest + import sshuttle.firewall @@ -59,6 +63,21 @@ def test_rewrite_etc_hosts(tmpdir): assert orig_hosts.computehash() == new_hosts.computehash() +@patch('os.link') +@patch('os.rename') +def test_rewrite_etc_hosts_no_overwrite(mock_link, mock_rename, tmpdir): + mock_link.side_effect = OSError + mock_rename.side_effect = OSError + + with pytest.raises(OSError): + os.link('/test_from', '/test_to') + + with pytest.raises(OSError): + os.rename('/test_from', '/test_to') + + test_rewrite_etc_hosts(tmpdir) + + def test_subnet_weight(): subnets = [ (AF_INET, 16, 0, '192.168.0.0', 0, 0), @@ -123,7 +142,7 @@ def test_main(mock_get_method, mock_setup_daemon, mock_rewrite_etc_hosts): [(AF_INET6, u'2404:6800:4004:80c::33')], AF_INET6, [(AF_INET6, 64, False, u'2404:6800:4004:80c::', 0, 0), - (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 80, 80)], + (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 80, 80)], True, None, '0x01'), @@ -132,7 +151,7 @@ def test_main(mock_get_method, mock_setup_daemon, mock_rewrite_etc_hosts): [(AF_INET, u'1.2.3.33')], AF_INET, [(AF_INET, 24, False, u'1.2.3.0', 8000, 9000), - (AF_INET, 32, True, u'1.2.3.66', 8080, 8080)], + (AF_INET, 32, True, u'1.2.3.66', 8080, 8080)], True, None, '0x01'),