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, opt.ttl) 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, opt.ttl) 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