Example #1
0
def do_iptables_nat(port, dnsport, family, subnets, udp):
    # only ipv4 supported with NAT
    if family != socket.AF_INET:
        raise Exception(
            'Address family "%s" unsupported by nat method'
            % family_to_string(family))
    if udp:
        raise Exception("UDP not supported by nat method")

    table = "nat"

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

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

    chain = 'sshuttle-%s' % port

    # basic cleanup/setup of chains
    if ipt_chain_exists(family, table, chain):
        nonfatal(ipt, '-D', 'OUTPUT', '-j', chain)
        nonfatal(ipt, '-D', 'PREROUTING', '-j', chain)
        nonfatal(ipt, '-F', chain)
        ipt('-X', chain)

    if subnets or dnsport:
        ipt('-N', chain)
        ipt('-F', chain)
        ipt('-I', 'OUTPUT', '1', '-j', chain)
        ipt('-I', 'PREROUTING', '1', '-j', chain)

    if subnets:
        # create new subnet entries.  Note that we're sorting in a very
        # particular order: we need to go from most-specific (largest swidth)
        # to least-specific, and at any given level of specificity, we want
        # excludes to come first.  That's why the columns are in such a non-
        # intuitive order.
        for f, swidth, sexclude, snet \
                in sorted(subnets, key=lambda s: s[1], reverse=True):
            if sexclude:
                ipt('-A', chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-p', 'tcp')
            else:
                ipt_ttl('-A', chain, '-j', 'REDIRECT',
                        '--dest', '%s/%s' % (snet, swidth),
                        '-p', 'tcp',
                        '--to-ports', str(port))

    if dnsport:
        nslist = resolvconf_nameservers()
        for f, ip in filter(lambda i: i[0] == family, nslist):
            ipt_ttl('-A', chain, '-j', 'REDIRECT',
                    '--dest', '%s/32' % ip,
                    '-p', 'udp',
                    '--dport', '53',
                    '--to-ports', str(dnsport))
Example #2
0
def do_iptables_nat(port, dnsport, family, subnets, udp):
    # only ipv4 supported with NAT
    if family != socket.AF_INET:
        raise Exception(
            'Address family "%s" unsupported by nat method'
            % family_to_string(family))
    if udp:
        raise Exception("UDP not supported by nat method")

    table = "nat"

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

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

    chain = 'sshuttle-%s' % port

    # basic cleanup/setup of chains
    if ipt_chain_exists(family, table, chain):
        nonfatal(ipt, '-D', 'OUTPUT', '-j', chain)
        nonfatal(ipt, '-D', 'PREROUTING', '-j', chain)
        nonfatal(ipt, '-F', chain)
        ipt('-X', chain)

    if subnets or dnsport:
        ipt('-N', chain)
        ipt('-F', chain)
        ipt('-I', 'OUTPUT', '1', '-j', chain)
        ipt('-I', 'PREROUTING', '1', '-j', chain)

    if subnets:
        # create new subnet entries.  Note that we're sorting in a very
        # particular order: we need to go from most-specific (largest swidth)
        # to least-specific, and at any given level of specificity, we want
        # excludes to come first.  That's why the columns are in such a non-
        # intuitive order.
        for f, swidth, sexclude, snet \
                in sorted(subnets, key=lambda s: s[1], reverse=True):
            if sexclude:
                ipt('-A', chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-p', 'tcp')
            else:
                ipt_ttl('-A', chain, '-j', 'REDIRECT',
                        '--dest', '%s/%s' % (snet, swidth),
                        '-p', 'tcp',
                        '--to-ports', str(port))

    if dnsport:
        nslist = resolvconf_nameservers()
        for f, ip in filter(lambda i: i[0] == family, nslist):
            ipt_ttl('-A', chain, '-j', 'REDIRECT',
                    '--dest', '%s/32' % ip,
                    '-p', 'udp',
                    '--dport', '53',
                    '--to-ports', str(dnsport))
Example #3
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\n' % ' '.join(argv))
    rv = ssubprocess.call(argv)
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
Example #4
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\n' % ' '.join(argv))
    rv = ssubprocess.call(argv)
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
Example #5
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']
    p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE)
    for line in p.stdout:
        if line.startswith('Chain %s ' % name):
            return True
    rv = p.wait()
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
Example #6
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']
    p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE)
    for line in p.stdout:
        if line.startswith('Chain %s ' % name):
            return True
    rv = p.wait()
    if rv:
        raise Fatal('%r returned %d' % (argv, rv))
Example #7
0
def do_pfctl(port, dnsport, family, subnets, udp):
    # TODO: pf does support IPv6, but for phase one, let's pretend it doesn't
    if family not in [socket.AF_INET, ]:
        raise Exception(
            'Address family "%s" unsupported by pf method'
            % family_to_string(family))
    if udp:
        raise Exception("UDP currently not supported by pf method")

    sport = str(port)
    xsport = str(port + 1)

    # TODO: add forwarding from sport to subnets
    # TODO: determine requirements for divertsock? Necessary with pfctl?
    pass
Example #8
0
def do_ipfw(port, dnsport, family, subnets, udp):
    # IPv6 not supported
    if family not in [socket.AF_INET, ]:
        raise Exception(
            'Address family "%s" unsupported by ipfw method'
            % family_to_string(family))
    if udp:
        raise Exception("UDP not supported by ipfw method")

    sport = str(port)
    xsport = str(port + 1)

    # cleanup any existing rules
    if ipfw_rule_exists(port):
        ipfw('delete', sport)

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

    if subnets or dnsport:
        sysctl_set('net.inet.ip.fw.enable', 1)
        changed = sysctl_set('net.inet.ip.scopedroute', 0, permanent=True)
        if changed:
            log("\n"
                "        WARNING: ONE-TIME NETWORK DISRUPTION:\n"
                "        =====================================\n"
                "sshuttle has changed a MacOS kernel setting to work around\n"
                "a bug in MacOS 10.6.  This will cause your network to drop\n"
                "within 5-10 minutes unless you restart your network\n"
                "interface (change wireless networks or unplug/plug the\n"
                "ethernet port) NOW, then restart sshuttle.  The fix is\n"
                "permanent; you only have to do this once.\n\n")
            sys.exit(1)

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

    if subnets:
        # create new subnet entries
        for f, swidth, sexclude, snet \
                in sorted(subnets, key=lambda s: s[1], reverse=True):
            if sexclude:
                ipfw('add', sport, 'skipto', xsport,
                     'tcp',
                     'from', 'any', 'to', '%s/%s' % (snet, swidth))
            else:
                ipfw('add', sport, 'fwd', '127.0.0.1,%d' % port,
                     'tcp',
                     'from', 'any', 'to', '%s/%s' % (snet, swidth),
                     'not', 'ipttl', '42', 'keep-state', 'setup')

    # This part is much crazier than it is on Linux, because MacOS (at least
    # 10.6, and probably other versions, and maybe FreeBSD too) doesn't
    # correctly fixup the dstip/dstport for UDP packets when it puts them
    # through a 'fwd' rule.  It also doesn't fixup the srcip/srcport in the
    # response packet.  In Linux iptables, all that happens magically for us,
    # so we just redirect the packets and relax.
    #
    # On MacOS, we have to fix the ports ourselves.  For that, we use a
    # 'divert' socket, which receives raw packets and lets us mangle them.
    #
    # Here's how it works.  Let's say the local DNS server is 1.1.1.1:53,
    # and the remote DNS server is 2.2.2.2:53, and the local transproxy port
    # is 10.0.0.1:12300, and a client machine is making a request from
    # 10.0.0.5:9999. We see a packet like this:
    #    10.0.0.5:9999 -> 1.1.1.1:53
    # Since the destip:port matches one of our local nameservers, it will
    # match a 'fwd' rule, thus grabbing it on the local machine.  However,
    # the local kernel will then see a packet addressed to *:53 and
    # not know what to do with it; there's nobody listening on port 53.  Thus,
    # we divert it, rewriting it into this:
    #    10.0.0.5:9999 -> 10.0.0.1:12300
    # This gets proxied out to the server, which sends it to 2.2.2.2:53,
    # and the answer comes back, and the proxy sends it back out like this:
    #    10.0.0.1:12300 -> 10.0.0.5:9999
    # But that's wrong!  The original machine expected an answer from
    # 1.1.1.1:53, so we have to divert the *answer* and rewrite it:
    #    1.1.1.1:53 -> 10.0.0.5:9999
    #
    # See?  Easy stuff.
    if dnsport:
        divertsock = socket.socket(socket.AF_INET, socket.SOCK_RAW,
                                   IPPROTO_DIVERT)
        divertsock.bind(('0.0.0.0', port))  # IP field is ignored

        nslist = resolvconf_nameservers()
        for f, ip in filter(lambda i: i[0] == family, nslist):
            # relabel and then catch outgoing DNS requests
            ipfw('add', sport, 'divert', sport,
                 'udp',
                 'from', 'any', 'to', '%s/32' % ip, '53',
                 'not', 'ipttl', '42')
        # relabel DNS responses
        ipfw('add', sport, 'divert', sport,
             'udp',
             'from', 'any', str(dnsport), 'to', 'any',
             'not', 'ipttl', '42')

        def do_wait():
            while 1:
                r, w, x = select.select([sys.stdin, divertsock], [], [])
                if divertsock in r:
                    _handle_diversion(divertsock, dnsport)
                if sys.stdin in r:
                    return
    else:
        do_wait = None

    return do_wait
Example #9
0
def do_iptables_tproxy(port, dnsport, family, subnets, udp):
    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 = 'sshuttle-m-%s' % port
    tproxy_chain = 'sshuttle-t-%s' % port
    divert_chain = 'sshuttle-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)

    if subnets or dnsport:
        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', '1', '-j', mark_chain)
        ipt('-I', 'PREROUTING', '1', '-j', tproxy_chain)
        ipt('-A', divert_chain, '-j', 'MARK', '--set-mark', '1')
        ipt('-A', divert_chain, '-j', 'ACCEPT')
        ipt('-A', tproxy_chain, '-m', 'socket', '-j', divert_chain,
            '-m', 'tcp', '-p', 'tcp')
    if subnets and udp:
        ipt('-A', tproxy_chain, '-m', 'socket', '-j', divert_chain,
            '-m', 'udp', '-p', 'udp')

    if dnsport:
        nslist = resolvconf_nameservers()
        for f, ip in filter(lambda i: i[0] == family, nslist):
            ipt('-A', mark_chain, '-j', 'MARK', '--set-mark', '1',
                '--dest', '%s/32' % ip,
                '-m', 'udp', '-p', 'udp', '--dport', '53')
            ipt('-A', tproxy_chain, '-j', 'TPROXY', '--tproxy-mark', '0x1/0x1',
                '--dest', '%s/32' % ip,
                '-m', 'udp', '-p', 'udp', '--dport', '53',
                '--on-port', str(dnsport))

    if subnets:
        for f, swidth, sexclude, snet \
                in sorted(subnets, key=lambda s: s[1], reverse=True):
            if sexclude:
                ipt('-A', mark_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp')
                ipt('-A', tproxy_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp')
            else:
                ipt('-A', mark_chain, '-j', 'MARK',
                    '--set-mark', '1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp')
                ipt('-A', tproxy_chain, '-j', 'TPROXY',
                    '--tproxy-mark', '0x1/0x1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp',
                    '--on-port', str(port))

            if sexclude and udp:
                ipt('-A', mark_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp')
                ipt('-A', tproxy_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp')
            elif udp:
                ipt('-A', mark_chain, '-j', 'MARK',
                    '--set-mark', '1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp')
                ipt('-A', tproxy_chain, '-j', 'TPROXY',
                    '--tproxy-mark', '0x1/0x1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp',
                    '--on-port', str(port))
Example #10
0
def do_ipfw(port, dnsport, family, subnets, udp):
    # IPv6 not supported
    if family not in [socket.AF_INET, ]:
        raise Exception(
            'Address family "%s" unsupported by ipfw method'
            % family_to_string(family))
    if udp:
        raise Exception("UDP not supported by ipfw method")

    sport = str(port)
    xsport = str(port + 1)

    # cleanup any existing rules
    if ipfw_rule_exists(port):
        ipfw('delete', sport)

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

    if subnets or dnsport:
        sysctl_set('net.inet.ip.fw.enable', 1)
        changed = sysctl_set('net.inet.ip.scopedroute', 0, permanent=True)
        if changed:
            log("\n"
                "        WARNING: ONE-TIME NETWORK DISRUPTION:\n"
                "        =====================================\n"
                "sshuttle has changed a MacOS kernel setting to work around\n"
                "a bug in MacOS 10.6.  This will cause your network to drop\n"
                "within 5-10 minutes unless you restart your network\n"
                "interface (change wireless networks or unplug/plug the\n"
                "ethernet port) NOW, then restart sshuttle.  The fix is\n"
                "permanent; you only have to do this once.\n\n")
            sys.exit(1)

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

    if subnets:
        # create new subnet entries
        for f, swidth, sexclude, snet \
                in sorted(subnets, key=lambda s: s[1], reverse=True):
            if sexclude:
                ipfw('add', sport, 'skipto', xsport,
                     'tcp',
                     'from', 'any', 'to', '%s/%s' % (snet, swidth))
            else:
                ipfw('add', sport, 'fwd', '127.0.0.1,%d' % port,
                     'tcp',
                     'from', 'any', 'to', '%s/%s' % (snet, swidth),
                     'not', 'ipttl', '42', 'keep-state', 'setup')

    # This part is much crazier than it is on Linux, because MacOS (at least
    # 10.6, and probably other versions, and maybe FreeBSD too) doesn't
    # correctly fixup the dstip/dstport for UDP packets when it puts them
    # through a 'fwd' rule.  It also doesn't fixup the srcip/srcport in the
    # response packet.  In Linux iptables, all that happens magically for us,
    # so we just redirect the packets and relax.
    #
    # On MacOS, we have to fix the ports ourselves.  For that, we use a
    # 'divert' socket, which receives raw packets and lets us mangle them.
    #
    # Here's how it works.  Let's say the local DNS server is 1.1.1.1:53,
    # and the remote DNS server is 2.2.2.2:53, and the local transproxy port
    # is 10.0.0.1:12300, and a client machine is making a request from
    # 10.0.0.5:9999. We see a packet like this:
    #    10.0.0.5:9999 -> 1.1.1.1:53
    # Since the destip:port matches one of our local nameservers, it will
    # match a 'fwd' rule, thus grabbing it on the local machine.  However,
    # the local kernel will then see a packet addressed to *:53 and
    # not know what to do with it; there's nobody listening on port 53.  Thus,
    # we divert it, rewriting it into this:
    #    10.0.0.5:9999 -> 10.0.0.1:12300
    # This gets proxied out to the server, which sends it to 2.2.2.2:53,
    # and the answer comes back, and the proxy sends it back out like this:
    #    10.0.0.1:12300 -> 10.0.0.5:9999
    # But that's wrong!  The original machine expected an answer from
    # 1.1.1.1:53, so we have to divert the *answer* and rewrite it:
    #    1.1.1.1:53 -> 10.0.0.5:9999
    #
    # See?  Easy stuff.
    if dnsport:
        divertsock = socket.socket(socket.AF_INET, socket.SOCK_RAW,
                                   IPPROTO_DIVERT)
        divertsock.bind(('0.0.0.0', port))  # IP field is ignored

        nslist = resolvconf_nameservers()
        for f, ip in filter(lambda i: i[0] == family, nslist):
            # relabel and then catch outgoing DNS requests
            ipfw('add', sport, 'divert', sport,
                 'udp',
                 'from', 'any', 'to', '%s/32' % ip, '53',
                 'not', 'ipttl', '42')
        # relabel DNS responses
        ipfw('add', sport, 'divert', sport,
             'udp',
             'from', 'any', str(dnsport), 'to', 'any',
             'not', 'ipttl', '42')

        def do_wait():
            while 1:
                r, w, x = select.select([sys.stdin, divertsock], [], [])
                if divertsock in r:
                    _handle_diversion(divertsock, dnsport)
                if sys.stdin in r:
                    return
    else:
        do_wait = None

    return do_wait
Example #11
0
def do_iptables_tproxy(port, dnsport, family, subnets, udp):
    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 = 'sshuttle-m-%s' % port
    tproxy_chain = 'sshuttle-t-%s' % port
    divert_chain = 'sshuttle-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)

    if subnets or dnsport:
        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', '1', '-j', mark_chain)
        ipt('-I', 'PREROUTING', '1', '-j', tproxy_chain)
        ipt('-A', divert_chain, '-j', 'MARK', '--set-mark', '1')
        ipt('-A', divert_chain, '-j', 'ACCEPT')
        ipt('-A', tproxy_chain, '-m', 'socket', '-j', divert_chain,
            '-m', 'tcp', '-p', 'tcp')
    if subnets and udp:
        ipt('-A', tproxy_chain, '-m', 'socket', '-j', divert_chain,
            '-m', 'udp', '-p', 'udp')

    if dnsport:
        nslist = resolvconf_nameservers()
        for f, ip in filter(lambda i: i[0] == family, nslist):
            ipt('-A', mark_chain, '-j', 'MARK', '--set-mark', '1',
                '--dest', '%s/32' % ip,
                '-m', 'udp', '-p', 'udp', '--dport', '53')
            ipt('-A', tproxy_chain, '-j', 'TPROXY', '--tproxy-mark', '0x1/0x1',
                '--dest', '%s/32' % ip,
                '-m', 'udp', '-p', 'udp', '--dport', '53',
                '--on-port', str(dnsport))

    if subnets:
        for f, swidth, sexclude, snet \
                in sorted(subnets, key=lambda s: s[1], reverse=True):
            if sexclude:
                ipt('-A', mark_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp')
                ipt('-A', tproxy_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp')
            else:
                ipt('-A', mark_chain, '-j', 'MARK',
                    '--set-mark', '1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp')
                ipt('-A', tproxy_chain, '-j', 'TPROXY',
                    '--tproxy-mark', '0x1/0x1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'tcp', '-p', 'tcp',
                    '--on-port', str(port))

            if sexclude and udp:
                ipt('-A', mark_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp')
                ipt('-A', tproxy_chain, '-j', 'RETURN',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp')
            elif udp:
                ipt('-A', mark_chain, '-j', 'MARK',
                    '--set-mark', '1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp')
                ipt('-A', tproxy_chain, '-j', 'TPROXY',
                    '--tproxy-mark', '0x1/0x1',
                    '--dest', '%s/%s' % (snet, swidth),
                    '-m', 'udp', '-p', 'udp',
                    '--on-port', str(port))