Exemplo n.º 1
0
def flush_systemd_dns_cache():
    # If the user is using systemd-resolve for DNS resolution, it is
    # possible for the request to go through systemd-resolve before we
    # see it...and it may use a cached result instead of sending a
    # request that we can intercept. When sshuttle starts and stops,
    # this means that we should clear the cache!
    #
    # The command to do this was named systemd-resolve, but changed to
    # resolvectl in systemd 239.
    # https://github.com/systemd/systemd/blob/f8eb41003df1a4eab59ff9bec67b2787c9368dbd/NEWS#L3816

    p = None
    if helpers.which("resolvectl"):
        debug2("Flushing systemd's DNS resolver cache: "
               "resolvectl flush-caches")
        p = ssubprocess.Popen(["resolvectl", "flush-caches"],
                              stdout=ssubprocess.PIPE, env=helpers.get_env())
    elif helpers.which("systemd-resolve"):
        debug2("Flushing systemd's DNS resolver cache: "
               "systemd-resolve --flush-caches")
        p = ssubprocess.Popen(["systemd-resolve", "--flush-caches"],
                              stdout=ssubprocess.PIPE, env=helpers.get_env())

    if p:
        # Wait so flush is finished and process doesn't show up as defunct.
        rv = p.wait()
        if rv != 0:
            log("Received non-zero return code %d when flushing DNS resolver "
                "cache." % rv)
Exemplo n.º 2
0
def ipfw(*args):
    argv = ['ipfw', '-q'] + list(args)
    debug1('>> %s' % ' '.join(argv))
    rv = ssubprocess.call(argv, env=get_env())
    # No env: No output. (Or error that won't be parsed.)
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
Exemplo n.º 3
0
def _check_smb(hostname):
    return
    global _smb_ok
    if not _smb_ok:
        return
    debug2(' > smb: %s' % hostname)
    argv = ['smbclient', '-U', '%', '-L', hostname]
    try:
        p = ssubprocess.Popen(argv,
                              stdout=ssubprocess.PIPE,
                              stderr=null,
                              env=get_env())
        lines = p.stdout.readlines()
        p.wait()
    except OSError:
        _, e = sys.exc_info()[:2]
        log('%r failed: %r' % (argv, e))
        _smb_ok = False
        return

    lines.reverse()

    # junk at top
    while lines:
        line = lines.pop().strip()
        if re.match(r'Server\s+', line):
            break

    # server list section:
    #    Server   Comment
    #    ------   -------
    while lines:
        line = lines.pop().strip()
        if not line or re.match(r'-+\s+-+', line):
            continue
        if re.match(r'Workgroup\s+Master', line):
            break
        words = line.split()
        hostname = words[0].lower()
        debug3('<    %s' % hostname)
        check_host(hostname)

    # workgroup list section:
    #   Workgroup  Master
    #   ---------  ------
    while lines:
        line = lines.pop().strip()
        if re.match(r'-+\s+', line):
            continue
        if not line:
            break
        words = line.split()
        (workgroup, hostname) = (words[0].lower(), words[1].lower())
        debug3('<    group(%s) -> %s' % (workgroup, hostname))
        check_host(hostname)
        check_workgroup(workgroup)

    if lines:
        assert (0)
Exemplo n.º 4
0
def nft(family, table, action, *args):
    if family in (socket.AF_INET, socket.AF_INET6):
        argv = ['nft', action, 'inet', table] + list(args)
    else:
        raise Exception('Unsupported family "%s"' % family_to_string(family))
    debug1('%s' % ' '.join(argv))
    rv = ssubprocess.call(argv, env=get_env())
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
Exemplo n.º 5
0
def ipt(family, table, *args):
    if family == socket.AF_INET6:
        argv = ['ip6tables', '-t', table] + list(args)
    elif family == socket.AF_INET:
        argv = ['iptables', '-t', table] + list(args)
    else:
        raise Exception('Unsupported family "%s"' % family_to_string(family))
    debug1('%s' % ' '.join(argv))
    rv = ssubprocess.call(argv, env=get_env())
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
Exemplo n.º 6
0
def pfctl(args, stdin=None):
    argv = ['pfctl'] + shlex.split(args)
    debug1('>> %s' % ' '.join(argv))
    p = ssubprocess.Popen(argv, stdin=ssubprocess.PIPE,
                          stdout=ssubprocess.PIPE,
                          stderr=ssubprocess.PIPE,
                          env=get_env())
    o = p.communicate(stdin)
    if p.returncode:
        raise Fatal('%r returned %d' % (argv, p.returncode))

    return o
Exemplo n.º 7
0
def flush_systemd_dns_cache():
    # If the user is using systemd-resolve for DNS resolution, it is
    # possible for the request to go through systemd-resolve before we
    # see it...and it may use a cached result instead of sending a
    # request that we can intercept. When sshuttle starts and stops,
    # this means that we should clear the cache!
    #
    # The command to do this was named systemd-resolve, but changed to
    # resolvectl in systemd 239.
    # https://github.com/systemd/systemd/blob/f8eb41003df1a4eab59ff9bec67b2787c9368dbd/NEWS#L3816

    if helpers.which("resolvectl"):
        debug2("Flushing systemd's DNS resolver cache: "
               "resolvectl flush-caches")
        ssubprocess.Popen(["resolvectl", "flush-caches"],
                          stdout=ssubprocess.PIPE, env=helpers.get_env())
    elif helpers.which("systemd-resolve"):
        debug2("Flushing systemd's DNS resolver cache: "
               "systemd-resolve --flush-caches")
        ssubprocess.Popen(["systemd-resolve", "--flush-caches"],
                          stdout=ssubprocess.PIPE, env=helpers.get_env())
Exemplo n.º 8
0
def _fill_oldctls(prefix):
    argv = ['sysctl', prefix]
    p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, env=get_env())
    for line in p.stdout:
        line = line.decode()
        assert (line[-1] == '\n')
        (k, v) = line[:-1].split(': ', 1)
        _oldctls[k] = v.strip()
    rv = p.wait()
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
    if not line:
        raise Fatal('%r returned no data' % (argv, ))
Exemplo n.º 9
0
def ipt_chain_exists(family, table, name):
    if family == socket.AF_INET6:
        cmd = 'ip6tables'
    elif family == socket.AF_INET:
        cmd = 'iptables'
    else:
        raise Exception('Unsupported family "%s"' % family_to_string(family))
    argv = [cmd, '-t', table, '-nL']
    try:
        output = ssubprocess.check_output(argv, env=get_env())
        for line in output.decode('ASCII').split('\n'):
            if line.startswith('Chain %s ' % name):
                return True
    except ssubprocess.CalledProcessError as e:
        raise Fatal('%r returned %d' % (argv, e.returncode))
Exemplo n.º 10
0
def ipfw_rule_exists(n):
    argv = ['ipfw', 'list']
    p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, env=get_env())

    found = False
    for line in p.stdout:
        if line.startswith(b'%05d ' % n):
            if not ('ipttl 63' in line or 'check-state' in line):
                log('non-sshuttle ipfw rule: %r' % line.strip())
                raise Fatal('non-sshuttle ipfw rule #%d already exists!' % n)
            found = True
    rv = p.wait()
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
    return found
Exemplo n.º 11
0
def pfctl(args, stdin=None):
    argv = ['pfctl'] + shlex.split(args)
    debug1('>> %s' % ' '.join(argv))
    p = ssubprocess.Popen(argv, stdin=ssubprocess.PIPE,
                          stdout=ssubprocess.PIPE,
                          stderr=ssubprocess.PIPE,
                          env=get_env())
    o = p.communicate(stdin)
    if p.returncode:
        log('%r returned %d, stdout and stderr follows: ' %
            (argv, p.returncode))
        log("stdout:\n%s" % o[0].decode("ascii"))
        log("stderr:\n%s" % o[1].decode("ascii"))
        raise Fatal('%r returned %d' % (argv, p.returncode))

    return o
Exemplo n.º 12
0
def _check_netstat():
    debug2(' > netstat')
    argv = ['netstat', '-n']
    try:
        p = ssubprocess.Popen(argv,
                              stdout=ssubprocess.PIPE,
                              stderr=null,
                              env=get_env())
        content = p.stdout.read().decode("ASCII")
        p.wait()
    except OSError:
        _, e = sys.exc_info()[:2]
        log('%r failed: %r' % (argv, e))
        return

    for ip in re.findall(r'\d+\.\d+\.\d+\.\d+', content):
        debug3('<    %s' % ip)
        check_host(ip)
Exemplo n.º 13
0
def _list_routes(argv, extract_route):
    # FIXME: IPv4 only
    p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, env=get_env())
    routes = []
    for line in p.stdout:
        if not line.strip():
            continue
        ipw, mask = extract_route(line.decode("ASCII"))
        if not ipw:
            continue
        width = min(ipw[1], mask)
        ip = ipw[0] & _shl(_shl(1, width) - 1, 32 - width)
        routes.append(
            (socket.AF_INET, socket.inet_ntoa(struct.pack('!I', ip)), width))
    rv = p.wait()
    if rv != 0:
        log('WARNING: %r returned %d' % (argv, rv))

    return routes
Exemplo n.º 14
0
def _check_netstat():
    debug2(' > netstat')
    argv = ['netstat', '-n']
    try:
        p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE, stderr=null,
                              env=get_env())
        content = p.stdout.read().decode("ASCII")
        p.wait()
    except OSError:
        _, e = sys.exc_info()[:2]
        log('%r failed: %r' % (argv, e))
        return

    # The same IPs may appear multiple times. Consolidate them so the
    # debug message doesn't print the same IP repeatedly.
    ip_list = []
    for ip in re.findall(r'\d+\.\d+\.\d+\.\d+', content):
        if ip not in ip_list:
            ip_list.append(ip)

    for ip in sorted(ip_list):
        debug3('<    %s' % ip)
        check_host(ip)
Exemplo n.º 15
0
def _sysctl_set(name, val):
    argv = ['sysctl', '-w', '%s=%s' % (name, val)]
    debug1('>> %s' % ' '.join(argv))
    return ssubprocess.call(argv, stdout=open(os.devnull, 'w'), env=get_env())
Exemplo n.º 16
0
 def enable(self):
     returncode = ssubprocess.call(['kldload', 'pf'], env=get_env())
     # No env: No output.
     super(FreeBsd, self).enable()
     if returncode == 0:
         _pf_context['loaded_by_sshuttle'] = True
Exemplo n.º 17
0
def ipfw_noexit(*args):
    argv = ['ipfw', '-q'] + list(args)
    debug1('>> %s' % ' '.join(argv))
    ssubprocess.call(argv, env=get_env())
Exemplo n.º 18
0
 def disable(self, anchor):
     super(FreeBsd, self).disable(anchor)
     if _pf_context['loaded_by_sshuttle'] and \
             _pf_context['started_by_sshuttle'] == 0:
         ssubprocess.call(['kldunload', 'pf'], env=get_env())
Exemplo n.º 19
0
def test_setup_firewall_freebsd(mock_pf_get_dev, mock_ioctl, mock_pfctl,
                                mock_subprocess_call):
    mock_pfctl.side_effect = pfctl

    method = get_method('pf')
    assert method.name == 'pf'

    method.setup_firewall(
        1024, 1026, [(AF_INET6, u'2404:6800:4004:80c::33')], AF_INET6,
        [(AF_INET6, 64, False, u'2404:6800:4004:80c::', 8000, 9000),
         (AF_INET6, 128, True, u'2404:6800:4004:80c::101f', 8080, 8080)],
        False, None)

    assert mock_pfctl.mock_calls == [
        call('-s all'),
        call(
            '-a sshuttle6-1024 -f /dev/stdin',
            b'table <dns_servers> {2404:6800:4004:80c::33}\n'
            b'rdr pass on lo0 inet6 proto tcp from ! ::1 to '
            b'2404:6800:4004:80c::/64 port 8000:9000 -> ::1 port 1024\n'
            b'rdr pass on lo0 inet6 proto udp '
            b'to <dns_servers> port 53 -> ::1 port 1026\n'
            b'pass out route-to lo0 inet6 proto tcp to '
            b'2404:6800:4004:80c::/64 port 8000:9000 keep state\n'
            b'pass out inet6 proto tcp to '
            b'2404:6800:4004:80c::101f/128 port 8080:8080\n'
            b'pass out route-to lo0 inet6 proto udp '
            b'to <dns_servers> port 53 keep state\n'),
        call('-e'),
    ]
    assert call(['kldload', 'pf'], env=get_env()) in \
        mock_subprocess_call.mock_calls
    mock_pf_get_dev.reset_mock()
    mock_ioctl.reset_mock()
    mock_pfctl.reset_mock()

    with pytest.raises(Exception) as excinfo:
        method.setup_firewall(1025, 1027, [(AF_INET, u'1.2.3.33')], AF_INET,
                              [(AF_INET, 24, False, u'1.2.3.0', 0, 0),
                               (AF_INET, 32, True, u'1.2.3.66', 80, 80)], True,
                              None)
    assert str(excinfo.value) == 'UDP not supported by pf method_name'
    assert mock_pf_get_dev.mock_calls == []
    assert mock_ioctl.mock_calls == []
    assert mock_pfctl.mock_calls == []

    method.setup_firewall(1025, 1027, [(AF_INET, u'1.2.3.33')], AF_INET,
                          [(AF_INET, 24, False, u'1.2.3.0', 0, 0),
                           (AF_INET, 32, True, u'1.2.3.66', 80, 80)], False,
                          None)
    assert mock_ioctl.mock_calls == [
        call(mock_pf_get_dev(), 0xC4704433, ANY),
        call(mock_pf_get_dev(), 0xCBE0441A, ANY),
        call(mock_pf_get_dev(), 0xCBE0441A, ANY),
        call(mock_pf_get_dev(), 0xC4704433, ANY),
        call(mock_pf_get_dev(), 0xCBE0441A, ANY),
        call(mock_pf_get_dev(), 0xCBE0441A, ANY),
    ]
    assert mock_pfctl.mock_calls == [
        call('-s all'),
        call(
            '-a sshuttle-1025 -f /dev/stdin',
            b'table <dns_servers> {1.2.3.33}\n'
            b'rdr pass on lo0 inet proto tcp from ! 127.0.0.1 '
            b'to 1.2.3.0/24 -> 127.0.0.1 port 1025\n'
            b'rdr pass on lo0 inet proto udp '
            b'to <dns_servers> port 53 -> 127.0.0.1 port 1027\n'
            b'pass out route-to lo0 inet proto tcp to 1.2.3.0/24 keep state\n'
            b'pass out inet proto tcp to 1.2.3.66/32 port 80:80\n'
            b'pass out route-to lo0 inet proto udp '
            b'to <dns_servers> port 53 keep state\n'),
        call('-e'),
    ]
    mock_pf_get_dev.reset_mock()
    mock_ioctl.reset_mock()
    mock_pfctl.reset_mock()

    method.restore_firewall(1025, AF_INET, False, None)
    method.restore_firewall(1024, AF_INET6, False, None)
    assert mock_ioctl.mock_calls == []
    assert mock_pfctl.mock_calls == [
        call('-a sshuttle-1025 -F all'),
        call('-a sshuttle6-1024 -F all'),
        call("-d"),
    ]
    mock_pf_get_dev.reset_mock()
    mock_pfctl.reset_mock()
    mock_ioctl.reset_mock()