mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-05-02 23:24:29 +02:00
Previously, it was possible to run sshuttle locally without using ssh and connecting to a remote server. In this configuration, traffic was redirected to the sshuttle server running on the localhost. However, the firewall needed to distinguish between traffic leaving the sshuttle server and traffic that originated from the machine that still needed to be routed through the sshuttle server. The TTL of the packets leaving the sshuttle server were manipulated to indicate to the firewall what should happen. The TTL was adjusted for all packets leaving the sshuttle server (even if it wasn't necessary because the server and client were running on different machines). Changing the TTL caused trouble and some machines, and the --ttl option was added as a workaround to change how the TTL was set for traffic leaving sshuttle. All of this added complexity to the code for a feature (running the server on localhost) that is likely only used for testing and rarely used by others. This commit updates the associated documentation, but doesn't fully fix the ipfw method since I am unable to test that. This change will also make sshuttle fail to work if -r is used to specify a localhost. Pull request #610 partially addresses that issue. For example, see: #240, #490, #660, #606.
134 lines
5.0 KiB
Python
134 lines
5.0 KiB
Python
import re
|
|
import socket
|
|
import platform
|
|
import sshuttle.helpers as helpers
|
|
import sshuttle.client as client
|
|
import sshuttle.firewall as firewall
|
|
import sshuttle.hostwatch as hostwatch
|
|
import sshuttle.ssyslog as ssyslog
|
|
from sshuttle.options import parser, parse_ipport
|
|
from sshuttle.helpers import family_ip_tuple, log, Fatal
|
|
from sshuttle.sudoers import sudoers
|
|
|
|
|
|
def main():
|
|
opt = parser.parse_args()
|
|
|
|
if opt.sudoers or opt.sudoers_no_modify:
|
|
if platform.platform().startswith('OpenBSD'):
|
|
log('Automatic sudoers does not work on BSD')
|
|
return 1
|
|
|
|
if not opt.sudoers_filename:
|
|
log('--sudoers-file must be set or omitted.')
|
|
return 1
|
|
|
|
sudoers(
|
|
user_name=opt.sudoers_user,
|
|
no_modify=opt.sudoers_no_modify,
|
|
file_name=opt.sudoers_filename
|
|
)
|
|
|
|
if opt.daemon:
|
|
opt.syslog = 1
|
|
if opt.wrap:
|
|
import sshuttle.ssnet as ssnet
|
|
ssnet.MAX_CHANNEL = opt.wrap
|
|
if opt.latency_buffer_size:
|
|
import sshuttle.ssnet as ssnet
|
|
ssnet.LATENCY_BUFFER_SIZE = opt.latency_buffer_size
|
|
helpers.verbose = opt.verbose
|
|
|
|
try:
|
|
if opt.firewall:
|
|
if opt.subnets or opt.subnets_file:
|
|
parser.error('exactly zero arguments expected')
|
|
return firewall.main(opt.method, opt.syslog)
|
|
elif opt.hostwatch:
|
|
return hostwatch.hw_main(opt.subnets, opt.auto_hosts)
|
|
else:
|
|
# parse_subnetports() is used to create a list of includes
|
|
# and excludes. It is called once for each parameter and
|
|
# returns a list of one or more items for each subnet (it
|
|
# can return more than one item when a hostname in the
|
|
# parameter resolves to multiple IP addresses. Here, we
|
|
# flatten these lists.
|
|
includes = [item for sublist in opt.subnets+opt.subnets_file
|
|
for item in sublist]
|
|
excludes = [item for sublist in opt.exclude for item in sublist]
|
|
|
|
if not includes and not opt.auto_nets:
|
|
parser.error('at least one subnet, subnet file, '
|
|
'or -N expected')
|
|
remotename = opt.remote
|
|
if remotename == '' or remotename == '-':
|
|
remotename = None
|
|
nslist = [family_ip_tuple(ns) for ns in opt.ns_hosts]
|
|
if opt.seed_hosts:
|
|
sh = re.split(r'[\s,]+', (opt.seed_hosts or "").strip())
|
|
elif opt.auto_hosts:
|
|
sh = []
|
|
else:
|
|
sh = None
|
|
if opt.listen:
|
|
ipport_v6 = None
|
|
ipport_v4 = None
|
|
lst = opt.listen.split(",")
|
|
for ip in lst:
|
|
family, ip, port = parse_ipport(ip)
|
|
if family == socket.AF_INET6:
|
|
ipport_v6 = (ip, port)
|
|
else:
|
|
ipport_v4 = (ip, port)
|
|
else:
|
|
# parse_ipport4('127.0.0.1:0')
|
|
ipport_v4 = "auto"
|
|
# parse_ipport6('[::1]:0')
|
|
ipport_v6 = "auto" if not opt.disable_ipv6 else None
|
|
try:
|
|
int(opt.tmark, 16)
|
|
except ValueError:
|
|
parser.error("--tmark must be a hexadecimal value")
|
|
opt.tmark = opt.tmark.lower() # make 'x' in 0x lowercase
|
|
if not opt.tmark.startswith("0x"): # accept without 0x prefix
|
|
opt.tmark = "0x%s" % opt.tmark
|
|
if opt.syslog:
|
|
ssyslog.start_syslog()
|
|
ssyslog.close_stdin()
|
|
ssyslog.stdout_to_syslog()
|
|
ssyslog.stderr_to_syslog()
|
|
return_code = client.main(ipport_v6, ipport_v4,
|
|
opt.ssh_cmd,
|
|
remotename,
|
|
opt.python,
|
|
opt.latency_control,
|
|
opt.latency_buffer_size,
|
|
opt.dns,
|
|
nslist,
|
|
opt.method,
|
|
sh,
|
|
opt.auto_hosts,
|
|
opt.auto_nets,
|
|
includes,
|
|
excludes,
|
|
opt.daemon,
|
|
opt.to_ns,
|
|
opt.pidfile,
|
|
opt.user,
|
|
opt.sudo_pythonpath,
|
|
opt.tmark)
|
|
|
|
if return_code == 0:
|
|
log('Normal exit code, exiting...')
|
|
else:
|
|
log('Abnormal exit code %d detected, failing...' % return_code)
|
|
return return_code
|
|
|
|
except Fatal as e:
|
|
log('fatal: %s' % e)
|
|
return 99
|
|
except KeyboardInterrupt:
|
|
log('\n')
|
|
log('Keyboard interrupt: exiting.')
|
|
return 1
|