예제 #1
0
    def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
                       user):
        if family not in [socket.AF_INET, socket.AF_INET6]:
            raise Exception(
                'Address family "%s" unsupported by pf method_name' %
                family_to_string(family))
        if udp:
            raise Exception("UDP not supported by pf method_name")

        if subnets:
            includes = []
            # If a given subnet is both included and excluded, list the
            # exclusion first; the table will ignore the second, opposite
            # definition
            for _, swidth, sexclude, snet, fport, lport \
                    in sorted(subnets, key=subnet_weight):
                includes.append(
                    (sexclude, b"%s/%d%s" %
                     (snet.encode("ASCII"), swidth, b" port %d:%d" %
                      (fport, lport) if fport else b"")))

        anchor = pf_get_anchor(family, port)
        pf.add_anchors(anchor)
        pf.add_rules(anchor, includes, port, dnsport, nslist, family)
        pf.enable()
예제 #2
0
    def restore_firewall(self, port, family, udp, user):
        # only ipv4 supported with NAT
        if family != socket.AF_INET:
            raise Exception(
                'Address family "%s" unsupported by nat method_name'
                % family_to_string(family))
        if udp:
            raise Exception("UDP not supported by nat method_name")

        table = "nat"

        def _ipt(*args):
            return ipt(family, table, *args)

        def _ipt_ttl(*args):
            return ipt_ttl(family, table, *args)

        def _ipm(*args):
            return ipt(family, "mangle", *args)

        chain = 'tshuttle-%s' % port

        # basic cleanup/setup of chains
        if ipt_chain_exists(family, table, chain):
            if user is not None:
                nonfatal(_ipm, '-D', 'OUTPUT', '-m', 'owner', '--uid-owner',
                         str(user), '-j', 'MARK', '--set-mark', str(port))
                args = '-m', 'mark', '--mark', str(port), '-j', chain
            else:
                args = '-j', chain
            nonfatal(_ipt, '-D', 'OUTPUT', *args)
            nonfatal(_ipt, '-D', 'PREROUTING', *args)
            nonfatal(_ipt, '-F', chain)
            _ipt('-X', chain)
예제 #3
0
    def restore_firewall(self, port, family, udp, user):
        if family not in [socket.AF_INET, socket.AF_INET6]:
            raise Exception(
                'Address family "%s" unsupported by tproxy method' %
                family_to_string(family))

        table = "mangle"

        def _ipt(*args):
            return ipt(family, table, *args)

        def _ipt_ttl(*args):
            return ipt_ttl(family, table, *args)

        mark_chain = 'tshuttle-m-%s' % port
        tproxy_chain = 'tshuttle-t-%s' % port
        divert_chain = 'tshuttle-d-%s' % port

        # basic cleanup/setup of chains
        if ipt_chain_exists(family, table, mark_chain):
            _ipt('-D', 'OUTPUT', '-j', mark_chain)
            _ipt('-F', mark_chain)
            _ipt('-X', mark_chain)

        if ipt_chain_exists(family, table, tproxy_chain):
            _ipt('-D', 'PREROUTING', '-j', tproxy_chain)
            _ipt('-F', tproxy_chain)
            _ipt('-X', tproxy_chain)

        if ipt_chain_exists(family, table, divert_chain):
            _ipt('-F', divert_chain)
            _ipt('-X', divert_chain)
예제 #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))
예제 #5
0
    def restore_firewall(self, port, family, udp, user):
        if family not in [socket.AF_INET, socket.AF_INET6]:
            raise Exception(
                'Address family "%s" unsupported by pf method_name' %
                family_to_string(family))
        if udp:
            raise Exception("UDP not supported by pf method_name")

        pf.disable(pf_get_anchor(family, port))
예제 #6
0
    def restore_firewall(self, port, family, udp, user):
        if family not in [socket.AF_INET]:
            raise Exception(
                'Address family "%s" unsupported by tproxy method' %
                family_to_string(family))

        ipfw_noexit('delete', '1')
        ipfw_noexit('table', '124', 'flush')
        ipfw_noexit('table', '125', 'flush')
        ipfw_noexit('table', '126', 'flush')
예제 #7
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))
예제 #8
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))
예제 #9
0
    def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
                       user):
        # IPv6 not supported
        if family not in [socket.AF_INET]:
            raise Exception(
                'Address family "%s" unsupported by ipfw method_name' %
                family_to_string(family))

        # XXX: Any risk from this?
        ipfw_noexit('delete', '1')

        while _changedctls:
            name = _changedctls.pop()
            oldval = _oldctls[name]
            _sysctl_set(name, oldval)

        if subnets or dnsport:
            sysctl_set('net.inet.ip.fw.enable', 1)

        ipfw('add', '1', 'check-state', 'ip', 'from', 'any', 'to', 'any')

        ipfw('add', '1', 'skipto', '2', 'tcp', 'from', 'any', 'to',
             'table(125)')
        ipfw('add', '1', 'fwd', '127.0.0.1,%d' % port, 'tcp', 'from', 'any',
             'to', 'table(126)', 'not', 'ipttl', '63', 'keep-state', 'setup')

        ipfw_noexit('table', '124', 'flush')
        dnscount = 0
        for _, ip in [i for i in nslist if i[0] == family]:
            ipfw('table', '124', 'add', '%s' % (ip))
            dnscount += 1
        if dnscount > 0:
            ipfw('add', '1', 'fwd', '127.0.0.1,%d' % dnsport, 'udp', 'from',
                 'any', 'to', 'table(124)', 'not', 'ipttl', '63')
        ipfw('add', '1', 'allow', 'udp', 'from', 'any', 'to', 'any', 'ipttl',
             '63')

        if subnets:
            # create new subnet entries
            for _, swidth, sexclude, snet in sorted(subnets,
                                                    key=lambda s: s[1],
                                                    reverse=True):
                if sexclude:
                    ipfw('table', '125', 'add', '%s/%s' % (snet, swidth))
            else:
                ipfw('table', '126', 'add', '%s/%s' % (snet, swidth))
예제 #10
0
    def setup_firewall(self, port, dnsport, nslist, family, subnets, udp,
                       user):
        # only ipv4 supported with NAT
        if family != socket.AF_INET:
            raise Exception(
                'Address family "%s" unsupported by nat method_name'
                % family_to_string(family))
        if udp:
            raise Exception("UDP not supported by nat method_name")

        table = "nat"

        def _ipt(*args):
            return ipt(family, table, *args)

        def _ipt_ttl(*args):
            return ipt_ttl(family, table, *args)

        def _ipm(*args):
            return ipt(family, "mangle", *args)

        chain = 'tshuttle-%s' % port

        # basic cleanup/setup of chains
        self.restore_firewall(port, family, udp, user)

        _ipt('-N', chain)
        _ipt('-F', chain)
        if user is not None:
            _ipm('-I', 'OUTPUT', '1', '-m', 'owner', '--uid-owner', str(user),
                 '-j', 'MARK', '--set-mark', str(port))
            args = '-m', 'mark', '--mark', str(port), '-j', chain
        else:
            args = '-j', chain

        _ipt('-I', 'OUTPUT', '1', *args)
        _ipt('-I', 'PREROUTING', '1', *args)

        # This TTL hack allows the client and server to run on the
        # same host. The connections the tshuttle server makes will
        # have TTL set to 63.
        _ipt_ttl('-A', chain, '-j', 'RETURN',  '-m', 'ttl', '--ttl', '63')

        # Redirect DNS traffic as requested. This includes routing traffic
        # to localhost DNS servers through tshuttle.
        for _, ip in [i for i in nslist if i[0] == family]:
            _ipt('-A', chain, '-j', 'REDIRECT',
                 '--dest', '%s/32' % ip,
                 '-p', 'udp',
                 '--dport', '53',
                 '--to-ports', str(dnsport))

        # Don't route any remaining local traffic through tshuttle.
        _ipt('-A', chain, '-j', 'RETURN',
             '-m', 'addrtype',
             '--dst-type', 'LOCAL')

        # create new subnet entries.
        for _, swidth, sexclude, snet, fport, lport \
                in sorted(subnets, key=subnet_weight, reverse=True):
            tcp_ports = ('-p', 'tcp')
            if fport:
                tcp_ports = tcp_ports + ('--dport', '%d:%d' % (fport, lport))

            if sexclude:
                _ipt('-A', chain, '-j', 'RETURN',
                     '--dest', '%s/%s' % (snet, swidth),
                     *tcp_ports)
            else:
                _ipt('-A', chain, '-j', 'REDIRECT',
                     '--dest', '%s/%s' % (snet, swidth),
                     *(tcp_ports + ('--to-ports', str(port))))
예제 #11
0
    def setup_firewall_tproxy(self, port, dnsport, nslist, family, subnets,
                              udp, user, tmark):
        if family not in [socket.AF_INET, socket.AF_INET6]:
            raise Exception(
                'Address family "%s" unsupported by tproxy method' %
                family_to_string(family))

        table = "mangle"

        def _ipt(*args):
            return ipt(family, table, *args)

        def _ipt_ttl(*args):
            return ipt_ttl(family, table, *args)

        def _ipt_proto_ports(proto, fport, lport):
            return proto + ('--dport', '%d:%d' % (fport, lport)) \
                    if fport else proto

        mark_chain = 'tshuttle-m-%s' % port
        tproxy_chain = 'tshuttle-t-%s' % port
        divert_chain = 'tshuttle-d-%s' % port

        # basic cleanup/setup of chains
        self.restore_firewall(port, family, udp, user)

        _ipt('-N', mark_chain)
        _ipt('-F', mark_chain)
        _ipt('-N', divert_chain)
        _ipt('-F', divert_chain)
        _ipt('-N', tproxy_chain)
        _ipt('-F', tproxy_chain)
        _ipt('-I', 'OUTPUT', tmark, '-j', mark_chain)
        _ipt('-I', 'PREROUTING', tmark, '-j', tproxy_chain)

        # Don't have packets sent to any of our local IP addresses go
        # through the tproxy or mark chains.
        #
        # Without this fix, if a large subnet is redirected through
        # tshuttle (i.e., 0/0), then the user may be unable to receive
        # UDP responses or connect to their own machine using an IP
        # besides (127.0.0.1). Prior to including these lines, the
        # documentation reminded the user to use -x to exclude their
        # own IP addresses to receive UDP responses if they are
        # redirecting a large subnet through tshuttle (i.e., 0/0).
        _ipt('-A', tproxy_chain, '-j', 'RETURN', '-m', 'addrtype',
             '--dst-type', 'LOCAL')
        _ipt('-A', mark_chain, '-j', 'RETURN', '-m', 'addrtype', '--dst-type',
             'LOCAL')

        _ipt('-A', divert_chain, '-j', 'MARK', '--set-mark', tmark)
        _ipt('-A', divert_chain, '-j', 'ACCEPT')
        _ipt('-A', tproxy_chain, '-m', 'socket', '-j', divert_chain, '-m',
             'tcp', '-p', 'tcp')

        if udp:
            _ipt('-A', tproxy_chain, '-m', 'socket', '-j', divert_chain, '-m',
                 'udp', '-p', 'udp')

        for _, ip in [i for i in nslist if i[0] == family]:
            _ipt('-A', mark_chain, '-j', 'MARK', '--set-mark', tmark, '--dest',
                 '%s/32' % ip, '-m', 'udp', '-p', 'udp', '--dport', '53')
            _ipt('-A', tproxy_chain, '-j', 'TPROXY', '--tproxy-mark',
                 '0x' + tmark + '/0x' + tmark, '--dest', '%s/32' % ip,
                 '-m', 'udp', '-p', 'udp', '--dport', '53', '--on-port',
                 str(dnsport))

        for _, swidth, sexclude, snet, fport, lport \
                in sorted(subnets, key=subnet_weight, reverse=True):
            tcp_ports = ('-p', 'tcp')
            tcp_ports = _ipt_proto_ports(tcp_ports, fport, lport)

            if sexclude:
                _ipt('-A', mark_chain, '-j', 'RETURN', '--dest',
                     '%s/%s' % (snet, swidth), '-m', 'tcp', *tcp_ports)
                _ipt('-A', tproxy_chain, '-j', 'RETURN', '--dest',
                     '%s/%s' % (snet, swidth), '-m', 'tcp', *tcp_ports)
            else:
                _ipt('-A', mark_chain, '-j', 'MARK', '--set-mark', tmark,
                     '--dest', '%s/%s' % (snet, swidth), '-m', 'tcp',
                     *tcp_ports)
                _ipt('-A', tproxy_chain, '-j', 'TPROXY', '--tproxy-mark',
                     '0x' + tmark + '/0x' + tmark, '--dest',
                     '%s/%s' % (snet, swidth), '-m', 'tcp',
                     *(tcp_ports + ('--on-port', str(port))))

            if udp:
                udp_ports = ('-p', 'udp')
                udp_ports = _ipt_proto_ports(udp_ports, fport, lport)

                if sexclude:
                    _ipt('-A', mark_chain, '-j', 'RETURN', '--dest',
                         '%s/%s' % (snet, swidth), '-m', 'udp', *udp_ports)
                    _ipt('-A', tproxy_chain, '-j', 'RETURN', '--dest',
                         '%s/%s' % (snet, swidth), '-m', 'udp', *udp_ports)
                else:
                    _ipt('-A', mark_chain, '-j', 'MARK', '--set-mark', tmark,
                         '--dest', '%s/%s' % (snet, swidth), '-m', 'udp',
                         *udp_ports)
                    _ipt('-A', tproxy_chain, '-j', 'TPROXY', '--tproxy-mark',
                         '0x' + tmark + '/0x' + tmark, '--dest',
                         '%s/%s' % (snet, swidth), '-m', 'udp',
                         *(udp_ports + ('--on-port', str(port))))