示例#1
0
def main(listenip_v6, listenip_v4, ssh_cmd, remotename, python,
         latency_control, dns, nslist, method_name, seed_hosts, auto_hosts,
         auto_nets, subnets_include, subnets_exclude, daemon, to_nameserver,
         pidfile, user, sudo_pythonpath):

    if daemon:
        try:
            check_daemon(pidfile)
        except Fatal as e:
            log("%s\n" % e)
            return 5
    debug1('Starting sshuttle proxy.\n')

    fw = FirewallClient(method_name, sudo_pythonpath)

    # Get family specific subnet lists
    if dns:
        nslist += resolvconf_nameservers()
        if to_nameserver is not None:
            to_nameserver = "%s@%s" % tuple(to_nameserver[1:])
    else:
        # option doesn't make sense if we aren't proxying dns
        to_nameserver = None

    subnets = subnets_include + subnets_exclude  # we don't care here
    subnets_v6 = [i for i in subnets if i[0] == socket.AF_INET6]
    nslist_v6 = [i for i in nslist if i[0] == socket.AF_INET6]
    subnets_v4 = [i for i in subnets if i[0] == socket.AF_INET]
    nslist_v4 = [i for i in nslist if i[0] == socket.AF_INET]

    # Check features available
    avail = fw.method.get_supported_features()
    required = Features()

    if listenip_v6 == "auto":
        if avail.ipv6:
            listenip_v6 = ('::1', 0)
        else:
            listenip_v6 = None

    if user is not None:
        if getpwnam is None:
            raise Fatal("Routing by user not available on this system.")
        try:
            user = getpwnam(user).pw_uid
        except KeyError:
            raise Fatal("User %s does not exist." % user)

    required.ipv6 = len(subnets_v6) > 0 or listenip_v6 is not None
    required.ipv4 = len(subnets_v4) > 0 or listenip_v4 is not None
    required.udp = avail.udp
    required.dns = len(nslist) > 0
    required.user = False if user is None else True

    # if IPv6 not supported, ignore IPv6 DNS servers
    if not required.ipv6:
        nslist_v6 = []
        nslist = nslist_v4

    fw.method.assert_features(required)

    if required.ipv6 and listenip_v6 is None:
        raise Fatal("IPv6 required but not listening.")

    # display features enabled
    debug1("IPv6 enabled: %r\n" % required.ipv6)
    debug1("UDP enabled: %r\n" % required.udp)
    debug1("DNS enabled: %r\n" % required.dns)
    debug1("User enabled: %r\n" % required.user)

    # bind to required ports
    if listenip_v4 == "auto":
        listenip_v4 = ('127.0.0.1', 0)

    if required.ipv4 and \
            not any(listenip_v4[0] == sex[1] for sex in subnets_v4):
        subnets_exclude.append((socket.AF_INET, listenip_v4[0], 32, 0, 0))

    if required.ipv6 and \
            not any(listenip_v6[0] == sex[1] for sex in subnets_v6):
        subnets_exclude.append((socket.AF_INET6, listenip_v6[0], 128, 0, 0))

    if listenip_v6 and listenip_v6[1] and listenip_v4 and listenip_v4[1]:
        # if both ports given, no need to search for a spare port
        ports = [
            0,
        ]
    else:
        # if at least one port missing, we have to search
        ports = range(12300, 9000, -1)
        # keep track of failed bindings and used ports to avoid trying to
        # bind to the same socket address twice in different listeners
        used_ports = []

    # search for free ports and try to bind
    last_e = None
    redirectport_v6 = 0
    redirectport_v4 = 0
    bound = False
    debug2('Binding redirector:')
    for port in ports:
        debug2(' %d' % port)
        tcp_listener = MultiListener()

        if required.udp:
            udp_listener = MultiListener(socket.SOCK_DGRAM)
        else:
            udp_listener = None

        if listenip_v6 and listenip_v6[1]:
            lv6 = listenip_v6
            redirectport_v6 = lv6[1]
        elif listenip_v6:
            lv6 = (listenip_v6[0], port)
            redirectport_v6 = port
        else:
            lv6 = None
            redirectport_v6 = 0

        if listenip_v4 and listenip_v4[1]:
            lv4 = listenip_v4
            redirectport_v4 = lv4[1]
        elif listenip_v4:
            lv4 = (listenip_v4[0], port)
            redirectport_v4 = port
        else:
            lv4 = None
            redirectport_v4 = 0

        try:
            tcp_listener.bind(lv6, lv4)
            if udp_listener:
                udp_listener.bind(lv6, lv4)
            bound = True
            used_ports.append(port)
            break
        except socket.error as e:
            if e.errno == errno.EADDRINUSE:
                last_e = e
                used_ports.append(port)
            else:
                raise e

    debug2('\n')
    if not bound:
        assert (last_e)
        raise last_e
    tcp_listener.listen(10)
    tcp_listener.print_listening("TCP redirector")
    if udp_listener:
        udp_listener.print_listening("UDP redirector")

    bound = False
    if required.dns:
        # search for spare port for DNS
        debug2('Binding DNS:')
        ports = range(12300, 9000, -1)
        for port in ports:
            debug2(' %d' % port)
            if port in used_ports: continue

            dns_listener = MultiListener(socket.SOCK_DGRAM)

            if listenip_v6:
                lv6 = (listenip_v6[0], port)
                dnsport_v6 = port
            else:
                lv6 = None
                dnsport_v6 = 0

            if listenip_v4:
                lv4 = (listenip_v4[0], port)
                dnsport_v4 = port
            else:
                lv4 = None
                dnsport_v4 = 0

            try:
                dns_listener.bind(lv6, lv4)
                bound = True
                used_ports.append(port)
                break
            except socket.error as e:
                if e.errno == errno.EADDRINUSE:
                    last_e = e
                    used_ports.append(port)
                else:
                    raise e
        debug2('\n')
        dns_listener.print_listening("DNS")
        if not bound:
            assert (last_e)
            raise last_e
    else:
        dnsport_v6 = 0
        dnsport_v4 = 0
        dns_listener = None

    # Last minute sanity checks.
    # These should never fail.
    # If these do fail, something is broken above.
    if subnets_v6:
        assert required.ipv6
        if redirectport_v6 == 0:
            raise Fatal("IPv6 subnets defined but not listening")

    if nslist_v6:
        assert required.dns
        assert required.ipv6
        if dnsport_v6 == 0:
            raise Fatal("IPv6 ns servers defined but not listening")

    if subnets_v4:
        if redirectport_v4 == 0:
            raise Fatal("IPv4 subnets defined but not listening")

    if nslist_v4:
        if dnsport_v4 == 0:
            raise Fatal("IPv4 ns servers defined but not listening")

    # setup method specific stuff on listeners
    fw.method.setup_tcp_listener(tcp_listener)
    if udp_listener:
        fw.method.setup_udp_listener(udp_listener)
    if dns_listener:
        fw.method.setup_udp_listener(dns_listener)

    # start the firewall
    fw.setup(subnets_include, subnets_exclude, nslist, redirectport_v6,
             redirectport_v4, dnsport_v6, dnsport_v4, required.udp, user)

    # start the client process
    try:
        return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
                     python, latency_control, dns_listener, seed_hosts,
                     auto_hosts, auto_nets, daemon, to_nameserver)
    finally:
        try:
            if daemon:
                # it's not our child anymore; can't waitpid
                fw.p.returncode = 0
            fw.done()
        finally:
            if daemon:
                daemon_cleanup()
示例#2
0
def main(listenip_v6, listenip_v4, ssh_cmd, remotename, python,
         latency_control, dns, nslist, method_name, seed_hosts, auto_hosts,
         auto_nets, subnets_include, subnets_exclude, daemon, to_nameserver,
         pidfile, user, sudo_pythonpath):

    if not remotename:
        print("WARNING: You must specify -r/--remote to securely route "
              "traffic to a remote machine. Running without -r/--remote "
              "is only recommended for testing.")

    if daemon:
        try:
            check_daemon(pidfile)
        except Fatal as e:
            log("%s\n" % e)
            return 5
    debug1('Starting sshuttle proxy (version %s).\n' % __version__)
    helpers.logprefix = 'c : '

    fw = FirewallClient(method_name, sudo_pythonpath)

    # If --dns is used, store the IP addresses that the client
    # normally uses for DNS lookups in nslist. The firewall needs to
    # redirect packets outgoing to this server to the remote host
    # instead.
    if dns:
        nslist += resolvconf_nameservers(True)
        if to_nameserver is not None:
            to_nameserver = "%s@%s" % tuple(to_nameserver[1:])
    else:
        # option doesn't make sense if we aren't proxying dns
        if to_nameserver and len(to_nameserver) > 0:
            print("WARNING: --to-ns option is ignored because --dns was not "
                  "used.")
        to_nameserver = None

    # Get family specific subnet lists. Also, the user may not specify
    # any subnets if they use --auto-nets. In this case, our subnets
    # list will be empty and the forwarded subnets will be determined
    # later by the server.
    subnets_v4 = [i for i in subnets_include if i[0] == socket.AF_INET]
    subnets_v6 = [i for i in subnets_include if i[0] == socket.AF_INET6]
    nslist_v4 = [i for i in nslist if i[0] == socket.AF_INET]
    nslist_v6 = [i for i in nslist if i[0] == socket.AF_INET6]

    # Get available features from the firewall method
    avail = fw.method.get_supported_features()

    # A feature is "required" if the user supplies us parameters which
    # implies that the feature is needed.
    required = Features()

    # Select the default addresses to bind to / listen to.

    # Assume IPv4 is always available and should always be enabled. If
    # a method doesn't provide IPv4 support or if we wish to run
    # ipv6-only, changes to this code are required.
    assert avail.ipv4
    required.ipv4 = True

    # listenip_v4 contains user specified value or it is set to "auto".
    if listenip_v4 == "auto":
        listenip_v4 = ('127.0.0.1', 0)

    # listenip_v6 is...
    #    None when IPv6 is disabled.
    #    "auto" when listen address is unspecified.
    #    The user specified address if provided by user
    if listenip_v6 is None:
        debug1("IPv6 disabled by --disable-ipv6\n")
    if listenip_v6 == "auto":
        if avail.ipv6:
            debug1("IPv6 enabled: Using default IPv6 listen address ::1\n")
            listenip_v6 = ('::1', 0)
        else:
            debug1("IPv6 disabled since it isn't supported by method "
                   "%s.\n" % fw.method.name)
            listenip_v6 = None

    # Make final decision about enabling IPv6:
    required.ipv6 = False
    if listenip_v6:
        required.ipv6 = True

    # If we get here, it is possible that listenip_v6 was user
    # specified but not supported by the current method.
    if required.ipv6 and not avail.ipv6:
        raise Fatal("An IPv6 listen address was supplied, but IPv6 is "
                    "disabled at your request or is unsupported by the %s "
                    "method." % fw.method.name)

    if user is not None:
        if getpwnam is None:
            raise Fatal("Routing by user not available on this system.")
        try:
            user = getpwnam(user).pw_uid
        except KeyError:
            raise Fatal("User %s does not exist." % user)
    required.user = False if user is None else True

    if not required.ipv6 and len(subnets_v6) > 0:
        print("WARNING: IPv6 subnets were ignored because IPv6 is disabled "
              "in sshuttle.")
        subnets_v6 = []
        subnets_include = subnets_v4

    required.udp = avail.udp  # automatically enable UDP if it is available
    required.dns = len(nslist) > 0

    # Remove DNS servers using IPv6.
    if required.dns:
        if not required.ipv6 and len(nslist_v6) > 0:
            print("WARNING: Your system is configured to use an IPv6 DNS "
                  "server but sshuttle is not using IPv6. Therefore DNS "
                  "traffic your system sends to the IPv6 DNS server won't "
                  "be redirected via sshuttle to the remote machine.")
            nslist_v6 = []
            nslist = nslist_v4

        if len(nslist) == 0:
            raise Fatal("Can't redirect DNS traffic since IPv6 is not "
                        "enabled in sshuttle and all of the system DNS "
                        "servers are IPv6.")

    # If we aren't using IPv6, we can safely ignore excluded IPv6 subnets.
    if not required.ipv6:
        orig_len = len(subnets_exclude)
        subnets_exclude = [
            i for i in subnets_exclude if i[0] == socket.AF_INET
        ]
        if len(subnets_exclude) < orig_len:
            print("WARNING: Ignoring one or more excluded IPv6 subnets "
                  "because IPv6 is not enabled.")

    # This will print error messages if we required a feature that
    # isn't available by the current method.
    fw.method.assert_features(required)

    # display features enabled
    def feature_status(label, enabled, available):
        msg = label + ": "
        if enabled:
            msg += "on"
        else:
            msg += "off "
            if available:
                msg += "(available)"
            else:
                msg += "(not available with %s method)" % fw.method.name
        debug1(msg + "\n")

    debug1("Method: %s\n" % fw.method.name)
    feature_status("IPv4", required.ipv4, avail.ipv4)
    feature_status("IPv6", required.ipv6, avail.ipv6)
    feature_status("UDP ", required.udp, avail.udp)
    feature_status("DNS ", required.dns, avail.dns)
    feature_status("User", required.user, avail.user)

    # Exclude traffic destined to our listen addresses.
    if required.ipv4 and \
            not any(listenip_v4[0] == sex[1] for sex in subnets_v4):
        subnets_exclude.append((socket.AF_INET, listenip_v4[0], 32, 0, 0))

    if required.ipv6 and \
            not any(listenip_v6[0] == sex[1] for sex in subnets_v6):
        subnets_exclude.append((socket.AF_INET6, listenip_v6[0], 128, 0, 0))

    # We don't print the IP+port of where we are listening here
    # because we do that below when we have identified the ports to
    # listen on.
    debug1("Subnets to forward through remote host (type, IP, cidr mask "
           "width, startPort, endPort):\n")
    for i in subnets_include:
        debug1("  " + str(i) + "\n")
    if auto_nets:
        debug1("NOTE: Additional subnets to forward may be added below by "
               "--auto-nets.\n")
    debug1("Subnets to exclude from forwarding:\n")
    for i in subnets_exclude:
        debug1("  " + str(i) + "\n")
    if required.dns:
        debug1("DNS requests normally directed at these servers will be "
               "redirected to remote:\n")
        for i in nslist:
            debug1("  " + str(i) + "\n")

    if listenip_v6 and listenip_v6[1] and listenip_v4 and listenip_v4[1]:
        # if both ports given, no need to search for a spare port
        ports = [
            0,
        ]
    else:
        # if at least one port missing, we have to search
        ports = range(12300, 9000, -1)
        # keep track of failed bindings and used ports to avoid trying to
        # bind to the same socket address twice in different listeners
        used_ports = []

    # search for free ports and try to bind
    last_e = None
    redirectport_v6 = 0
    redirectport_v4 = 0
    bound = False
    for port in ports:
        debug2('Trying to bind redirector on port %d\n' % port)
        tcp_listener = MultiListener()

        if required.udp:
            udp_listener = MultiListener(socket.SOCK_DGRAM)
        else:
            udp_listener = None

        if listenip_v6 and listenip_v6[1]:
            lv6 = listenip_v6
            redirectport_v6 = lv6[1]
        elif listenip_v6:
            lv6 = (listenip_v6[0], port)
            redirectport_v6 = port
        else:
            lv6 = None
            redirectport_v6 = 0

        if listenip_v4 and listenip_v4[1]:
            lv4 = listenip_v4
            redirectport_v4 = lv4[1]
        elif listenip_v4:
            lv4 = (listenip_v4[0], port)
            redirectport_v4 = port
        else:
            lv4 = None
            redirectport_v4 = 0

        try:
            tcp_listener.bind(lv6, lv4)
            if udp_listener:
                udp_listener.bind(lv6, lv4)
            bound = True
            used_ports.append(port)
            break
        except socket.error as e:
            if e.errno == errno.EADDRINUSE:
                last_e = e
                used_ports.append(port)
            else:
                raise e

    if not bound:
        assert (last_e)
        raise last_e
    tcp_listener.listen(10)
    tcp_listener.print_listening("TCP redirector")
    if udp_listener:
        udp_listener.print_listening("UDP redirector")

    bound = False
    if required.dns:
        # search for spare port for DNS
        ports = range(12300, 9000, -1)
        for port in ports:
            debug2('Trying to bind DNS redirector on port %d\n' % port)
            if port in used_ports:
                continue

            dns_listener = MultiListener(socket.SOCK_DGRAM)

            if listenip_v6:
                lv6 = (listenip_v6[0], port)
                dnsport_v6 = port
            else:
                lv6 = None
                dnsport_v6 = 0

            if listenip_v4:
                lv4 = (listenip_v4[0], port)
                dnsport_v4 = port
            else:
                lv4 = None
                dnsport_v4 = 0

            try:
                dns_listener.bind(lv6, lv4)
                bound = True
                used_ports.append(port)
                break
            except socket.error as e:
                if e.errno == errno.EADDRINUSE:
                    last_e = e
                    used_ports.append(port)
                else:
                    raise e

        dns_listener.print_listening("DNS")
        if not bound:
            assert (last_e)
            raise last_e
    else:
        dnsport_v6 = 0
        dnsport_v4 = 0
        dns_listener = None

    # Last minute sanity checks.
    # These should never fail.
    # If these do fail, something is broken above.
    if subnets_v6:
        assert required.ipv6
        if redirectport_v6 == 0:
            raise Fatal("IPv6 subnets defined but not listening")

    if nslist_v6:
        assert required.dns
        assert required.ipv6
        if dnsport_v6 == 0:
            raise Fatal("IPv6 ns servers defined but not listening")

    if subnets_v4:
        if redirectport_v4 == 0:
            raise Fatal("IPv4 subnets defined but not listening")

    if nslist_v4:
        if dnsport_v4 == 0:
            raise Fatal("IPv4 ns servers defined but not listening")

    # setup method specific stuff on listeners
    fw.method.setup_tcp_listener(tcp_listener)
    if udp_listener:
        fw.method.setup_udp_listener(udp_listener)
    if dns_listener:
        fw.method.setup_udp_listener(dns_listener)

    # start the firewall
    fw.setup(subnets_include, subnets_exclude, nslist, redirectport_v6,
             redirectport_v4, dnsport_v6, dnsport_v4, required.udp, user)

    # start the client process
    try:
        return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
                     python, latency_control, dns_listener, seed_hosts,
                     auto_hosts, auto_nets, daemon, to_nameserver)
    finally:
        try:
            if daemon:
                # it's not our child anymore; can't waitpid
                fw.p.returncode = 0
            fw.done()
            sdnotify.send(sdnotify.stop())

        finally:
            if daemon:
                daemon_cleanup()
示例#3
0
def main(listenip_v6, listenip_v4,
         ssh_cmd, remotename, python, latency_control, dns, nslist,
         method_name, seed_hosts, auto_nets,
         subnets_include, subnets_exclude, daemon, pidfile):

    if daemon:
        try:
            check_daemon(pidfile)
        except Fatal as e:
            log("%s\n" % e)
            return 5
    debug1('Starting sshuttle proxy.\n')

    fw = FirewallClient(method_name)

    # Get family specific subnet lists
    if dns:
        nslist += resolvconf_nameservers()

    subnets = subnets_include + subnets_exclude  # we don't care here
    subnets_v6 = [i for i in subnets if i[0] == socket.AF_INET6]
    nslist_v6 = [i for i in nslist if i[0] == socket.AF_INET6]
    subnets_v4 = [i for i in subnets if i[0] == socket.AF_INET]
    nslist_v4 = [i for i in nslist if i[0] == socket.AF_INET]

    # Check features available
    avail = fw.method.get_supported_features()
    required = Features()

    if listenip_v6 == "auto":
        if avail.ipv6:
            listenip_v6 = ('::1', 0)
        else:
            listenip_v6 = None

    required.ipv6 = len(subnets_v6) > 0 or len(nslist_v6) > 0 \
        or listenip_v6 is not None
    required.udp = avail.udp
    required.dns = len(nslist) > 0

    fw.method.assert_features(required)

    if required.ipv6 and listenip_v6 is None:
        raise Fatal("IPv6 required but not listening.")

    # display features enabled
    debug1("IPv6 enabled: %r\n" % required.ipv6)
    debug1("UDP enabled: %r\n" % required.udp)
    debug1("DNS enabled: %r\n" % required.dns)

    # bind to required ports
    if listenip_v4 == "auto":
        listenip_v4 = ('127.0.0.1', 0)

    if listenip_v6 and listenip_v6[1] and listenip_v4 and listenip_v4[1]:
        # if both ports given, no need to search for a spare port
        ports = [0, ]
    else:
        # if at least one port missing, we have to search
        ports = range(12300, 9000, -1)

    # search for free ports and try to bind
    last_e = None
    redirectport_v6 = 0
    redirectport_v4 = 0
    bound = False
    debug2('Binding redirector:')
    for port in ports:
        debug2(' %d' % port)
        tcp_listener = MultiListener()

        if required.udp:
            udp_listener = MultiListener(socket.SOCK_DGRAM)
        else:
            udp_listener = None

        if listenip_v6 and listenip_v6[1]:
            lv6 = listenip_v6
            redirectport_v6 = lv6[1]
        elif listenip_v6:
            lv6 = (listenip_v6[0], port)
            redirectport_v6 = port
        else:
            lv6 = None
            redirectport_v6 = 0

        if listenip_v4 and listenip_v4[1]:
            lv4 = listenip_v4
            redirectport_v4 = lv4[1]
        elif listenip_v4:
            lv4 = (listenip_v4[0], port)
            redirectport_v4 = port
        else:
            lv4 = None
            redirectport_v4 = 0

        try:
            tcp_listener.bind(lv6, lv4)
            if udp_listener:
                udp_listener.bind(lv6, lv4)
            bound = True
            break
        except socket.error as e:
            if e.errno == errno.EADDRINUSE:
                last_e = e
            else:
                raise e

    debug2('\n')
    if not bound:
        assert(last_e)
        raise last_e
    tcp_listener.listen(10)
    tcp_listener.print_listening("TCP redirector")
    if udp_listener:
        udp_listener.print_listening("UDP redirector")

    bound = False
    if required.dns:
        # search for spare port for DNS
        debug2('Binding DNS:')
        ports = range(12300, 9000, -1)
        for port in ports:
            debug2(' %d' % port)
            dns_listener = MultiListener(socket.SOCK_DGRAM)

            if listenip_v6:
                lv6 = (listenip_v6[0], port)
                dnsport_v6 = port
            else:
                lv6 = None
                dnsport_v6 = 0

            if listenip_v4:
                lv4 = (listenip_v4[0], port)
                dnsport_v4 = port
            else:
                lv4 = None
                dnsport_v4 = 0

            try:
                dns_listener.bind(lv6, lv4)
                bound = True
                break
            except socket.error as e:
                if e.errno == errno.EADDRINUSE:
                    last_e = e
                else:
                    raise e
        debug2('\n')
        dns_listener.print_listening("DNS")
        if not bound:
            assert(last_e)
            raise last_e
    else:
        dnsport_v6 = 0
        dnsport_v4 = 0
        dns_listener = None

    # Last minute sanity checks.
    # These should never fail.
    # If these do fail, something is broken above.
    if len(subnets_v6) > 0:
        assert required.ipv6
        if redirectport_v6 == 0:
            raise Fatal("IPv6 subnets defined but not listening")

    if len(nslist_v6) > 0:
        assert required.dns
        assert required.ipv6
        if dnsport_v6 == 0:
            raise Fatal("IPv6 ns servers defined but not listening")

    if len(subnets_v4) > 0:
        if redirectport_v4 == 0:
            raise Fatal("IPv4 subnets defined but not listening")

    if len(nslist_v4) > 0:
        if dnsport_v4 == 0:
            raise Fatal("IPv4 ns servers defined but not listening")

    # setup method specific stuff on listeners
    fw.method.setup_tcp_listener(tcp_listener)
    if udp_listener:
        fw.method.setup_udp_listener(udp_listener)
    if dns_listener:
        fw.method.setup_udp_listener(dns_listener)

    # start the firewall
    fw.setup(subnets_include, subnets_exclude, nslist,
             redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4,
             required.udp)

    # start the client process
    try:
        return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
                     python, latency_control, dns_listener,
                     seed_hosts, auto_nets, daemon)
    finally:
        try:
            if daemon:
                # it's not our child anymore; can't waitpid
                fw.p.returncode = 0
            fw.done()
        finally:
            if daemon:
                daemon_cleanup()
示例#4
0
def main(listenip_v6, listenip_v4,
         ssh_cmd, remotename, python, latency_control, dns, nslist,
         method_name, seed_hosts, auto_nets,
         subnets_include, subnets_exclude, daemon, pidfile):

    if daemon:
        try:
            check_daemon(pidfile)
        except Fatal as e:
            log("%s\n" % e)
            return 5
    debug1('Starting sshuttle proxy.\n')

    fw = FirewallClient(method_name)

    # Get family specific subnet lists
    if dns:
        nslist += resolvconf_nameservers()

    subnets = subnets_include + subnets_exclude  # we don't care here
    subnets_v6 = [i for i in subnets if i[0] == socket.AF_INET6]
    nslist_v6 = [i for i in nslist if i[0] == socket.AF_INET6]
    subnets_v4 = [i for i in subnets if i[0] == socket.AF_INET]
    nslist_v4 = [i for i in nslist if i[0] == socket.AF_INET]

    # Check features available
    avail = fw.method.get_supported_features()
    required = Features()

    if listenip_v6 == "auto":
        if avail.ipv6:
            listenip_v6 = ('::1', 0)
        else:
            listenip_v6 = None

    required.ipv6 = len(subnets_v6) > 0 or listenip_v6 is not None
    required.udp = avail.udp
    required.dns = len(nslist) > 0

    # if IPv6 not supported, ignore IPv6 DNS servers
    if not required.ipv6:
        nslist_v6 = []
        nslist = nslist_v4

    fw.method.assert_features(required)

    if required.ipv6 and listenip_v6 is None:
        raise Fatal("IPv6 required but not listening.")

    # display features enabled
    debug1("IPv6 enabled: %r\n" % required.ipv6)
    debug1("UDP enabled: %r\n" % required.udp)
    debug1("DNS enabled: %r\n" % required.dns)

    # bind to required ports
    if listenip_v4 == "auto":
        listenip_v4 = ('127.0.0.1', 0)

    if listenip_v6 and listenip_v6[1] and listenip_v4 and listenip_v4[1]:
        # if both ports given, no need to search for a spare port
        ports = [0, ]
    else:
        # if at least one port missing, we have to search
        ports = range(12300, 9000, -1)

    # search for free ports and try to bind
    last_e = None
    redirectport_v6 = 0
    redirectport_v4 = 0
    bound = False
    debug2('Binding redirector:')
    for port in ports:
        debug2(' %d' % port)
        tcp_listener = MultiListener()

        if required.udp:
            udp_listener = MultiListener(socket.SOCK_DGRAM)
        else:
            udp_listener = None

        if listenip_v6 and listenip_v6[1]:
            lv6 = listenip_v6
            redirectport_v6 = lv6[1]
        elif listenip_v6:
            lv6 = (listenip_v6[0], port)
            redirectport_v6 = port
        else:
            lv6 = None
            redirectport_v6 = 0

        if listenip_v4 and listenip_v4[1]:
            lv4 = listenip_v4
            redirectport_v4 = lv4[1]
        elif listenip_v4:
            lv4 = (listenip_v4[0], port)
            redirectport_v4 = port
        else:
            lv4 = None
            redirectport_v4 = 0

        try:
            tcp_listener.bind(lv6, lv4)
            if udp_listener:
                udp_listener.bind(lv6, lv4)
            bound = True
            break
        except socket.error as e:
            if e.errno == errno.EADDRINUSE:
                last_e = e
            else:
                raise e

    debug2('\n')
    if not bound:
        assert(last_e)
        raise last_e
    tcp_listener.listen(10)
    tcp_listener.print_listening("TCP redirector")
    if udp_listener:
        udp_listener.print_listening("UDP redirector")

    bound = False
    if required.dns:
        # search for spare port for DNS
        debug2('Binding DNS:')
        ports = range(12300, 9000, -1)
        for port in ports:
            debug2(' %d' % port)
            dns_listener = MultiListener(socket.SOCK_DGRAM)

            if listenip_v6:
                lv6 = (listenip_v6[0], port)
                dnsport_v6 = port
            else:
                lv6 = None
                dnsport_v6 = 0

            if listenip_v4:
                lv4 = (listenip_v4[0], port)
                dnsport_v4 = port
            else:
                lv4 = None
                dnsport_v4 = 0

            try:
                dns_listener.bind(lv6, lv4)
                bound = True
                break
            except socket.error as e:
                if e.errno == errno.EADDRINUSE:
                    last_e = e
                else:
                    raise e
        debug2('\n')
        dns_listener.print_listening("DNS")
        if not bound:
            assert(last_e)
            raise last_e
    else:
        dnsport_v6 = 0
        dnsport_v4 = 0
        dns_listener = None

    # Last minute sanity checks.
    # These should never fail.
    # If these do fail, something is broken above.
    if len(subnets_v6) > 0:
        assert required.ipv6
        if redirectport_v6 == 0:
            raise Fatal("IPv6 subnets defined but not listening")

    if len(nslist_v6) > 0:
        assert required.dns
        assert required.ipv6
        if dnsport_v6 == 0:
            raise Fatal("IPv6 ns servers defined but not listening")

    if len(subnets_v4) > 0:
        if redirectport_v4 == 0:
            raise Fatal("IPv4 subnets defined but not listening")

    if len(nslist_v4) > 0:
        if dnsport_v4 == 0:
            raise Fatal("IPv4 ns servers defined but not listening")

    # setup method specific stuff on listeners
    fw.method.setup_tcp_listener(tcp_listener)
    if udp_listener:
        fw.method.setup_udp_listener(udp_listener)
    if dns_listener:
        fw.method.setup_udp_listener(dns_listener)

    # start the firewall
    fw.setup(subnets_include, subnets_exclude, nslist,
             redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4,
             required.udp)

    # start the client process
    try:
        return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
                     python, latency_control, dns_listener,
                     seed_hosts, auto_nets, daemon)
    finally:
        try:
            if daemon:
                # it's not our child anymore; can't waitpid
                fw.p.returncode = 0
            fw.done()
        finally:
            if daemon:
                daemon_cleanup()
示例#5
0
def main(listenip_v6, listenip_v4,
         ssh_cmd, remotename, python, latency_control, dns, nslist,
         method_name, seed_hosts, auto_nets,
         subnets_include, subnets_exclude, syslog, daemon, pidfile):

    if syslog:
        ssyslog.start_syslog()
    if daemon:
        try:
            check_daemon(pidfile)
        except Fatal as e:
            log("%s\n" % e)
            return 5
    debug1('Starting sshuttle proxy.\n')

    fw = FirewallClient(method_name)

    features = fw.method.get_supported_features()
    if listenip_v6 == "auto":
        if features.ipv6:
            listenip_v6 = ('::1', 0)
        else:
            listenip_v6 = None

    if listenip_v4 == "auto":
        listenip_v4 = ('127.0.0.1', 0)

    udp = features.udp
    debug1("UDP enabled: %r\n" % udp)

    if listenip_v6 and listenip_v6[1] and listenip_v4 and listenip_v4[1]:
        # if both ports given, no need to search for a spare port
        ports = [0, ]
    else:
        # if at least one port missing, we have to search
        ports = range(12300, 9000, -1)

    # search for free ports and try to bind
    last_e = None
    redirectport_v6 = 0
    redirectport_v4 = 0
    bound = False
    debug2('Binding redirector:')
    for port in ports:
        debug2(' %d' % port)
        tcp_listener = MultiListener()
        tcp_listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

        if udp:
            udp_listener = MultiListener(socket.SOCK_DGRAM)
            udp_listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        else:
            udp_listener = None

        if listenip_v6 and listenip_v6[1]:
            lv6 = listenip_v6
            redirectport_v6 = lv6[1]
        elif listenip_v6:
            lv6 = (listenip_v6[0], port)
            redirectport_v6 = port
        else:
            lv6 = None
            redirectport_v6 = 0

        if listenip_v4 and listenip_v4[1]:
            lv4 = listenip_v4
            redirectport_v4 = lv4[1]
        elif listenip_v4:
            lv4 = (listenip_v4[0], port)
            redirectport_v4 = port
        else:
            lv4 = None
            redirectport_v4 = 0

        try:
            tcp_listener.bind(lv6, lv4)
            if udp_listener:
                udp_listener.bind(lv6, lv4)
            bound = True
            break
        except socket.error as e:
            if e.errno == errno.EADDRINUSE:
                last_e = e
            else:
                raise e

    debug2('\n')
    if not bound:
        assert(last_e)
        raise last_e
    tcp_listener.listen(10)
    tcp_listener.print_listening("TCP redirector")
    if udp_listener:
        udp_listener.print_listening("UDP redirector")

    bound = False
    if dns or nslist:
        if dns:
            nslist += resolvconf_nameservers()
        dns = True
        # search for spare port for DNS
        debug2('Binding DNS:')
        ports = range(12300, 9000, -1)
        for port in ports:
            debug2(' %d' % port)
            dns_listener = MultiListener(socket.SOCK_DGRAM)

            if listenip_v6:
                lv6 = (listenip_v6[0], port)
                dnsport_v6 = port
            else:
                lv6 = None
                dnsport_v6 = 0

            if listenip_v4:
                lv4 = (listenip_v4[0], port)
                dnsport_v4 = port
            else:
                lv4 = None
                dnsport_v4 = 0

            try:
                dns_listener.bind(lv6, lv4)
                bound = True
                break
            except socket.error as e:
                if e.errno == errno.EADDRINUSE:
                    last_e = e
                else:
                    raise e
        debug2('\n')
        dns_listener.print_listening("DNS")
        if not bound:
            assert(last_e)
            raise last_e
    else:
        dnsport_v6 = 0
        dnsport_v4 = 0
        dns_listener = None

    fw.method.check_settings(udp, dns)
    fw.method.setup_tcp_listener(tcp_listener)
    if udp_listener:
        fw.method.setup_udp_listener(udp_listener)
    if dns_listener:
        fw.method.setup_udp_listener(dns_listener)

    fw.setup(subnets_include, subnets_exclude, nslist,
             redirectport_v6, redirectport_v4, dnsport_v6, dnsport_v4,
             udp)

    try:
        return _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
                     python, latency_control, dns_listener,
                     seed_hosts, auto_nets, syslog,
                     daemon)
    finally:
        try:
            if daemon:
                # it's not our child anymore; can't waitpid
                fw.p.returncode = 0
            fw.done()
        finally:
            if daemon:
                daemon_cleanup()