TProxy support as well as NAT support.

This commit is contained in:
Brian May 2011-07-11 10:30:06 +10:00
parent 9a7412c08f
commit f41c6b62e5
3 changed files with 74 additions and 4 deletions

View File

@ -12,6 +12,7 @@ def got_signal(signum, frame):
_pidname = None
IP_TRANSPARENT = 19
def check_daemon(pidfile):
global _pidname
_pidname = os.path.abspath(pidfile)
@ -232,8 +233,11 @@ def onaccept_tcp(listener, method, mux, handlers):
return
else:
raise
dstip = original_dst(sock)
debug1('Accept: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
if method == "tproxy":
dstip = sock.getsockname();
else:
dstip = original_dst(sock)
debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
dstip[0],dstip[1]))
if dstip[1] == listener.getsockname()[1] and islocal(dstip[0], sock.family):
debug1("-- ignored: that's my address!\n")
@ -466,6 +470,9 @@ def main(listenip_v4,
fw = FirewallClient(redirectport_v4, subnets_include, subnets_exclude, dnsport_v4, method)
if fw.method == "tproxy":
tcp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1)
try:
return _main(tcp_listener, fw, ssh_cmd, remotename,
python, latency_control, dns_listener,

View File

@ -118,6 +118,67 @@ def do_iptables_nat(port, dnsport, family, subnets):
'--to-ports', str(dnsport))
def do_iptables_tproxy(port, dnsport, family, subnets):
if family not in [socket.AF_INET]:
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:
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))
def ipfw_rule_exists(n):
argv = ['ipfw', 'list']
p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE)
@ -408,6 +469,8 @@ def main(port_v4, dnsport_v4, method, syslog):
if method == "nat":
do_it = do_iptables_nat
elif method == "tproxy":
do_it = do_iptables_tproxy
elif method == "ipfw":
do_it = do_ipfw
else:

View File

@ -60,7 +60,7 @@ l,listen= transproxy to this ip address and port number [127.0.0.1:0]
H,auto-hosts scan for remote hostnames and update local /etc/hosts
N,auto-nets automatically determine subnets to route
dns capture local DNS requests and forward to the remote DNS server
method= auto, nat, or ipfw
method= auto, nat, tproxy, or ipfw
python= path to python interpreter on the remote server
r,remote= ssh hostname (and optional username) of remote sshuttle server
x,exclude= exclude this subnet (can be used more than once)
@ -120,7 +120,7 @@ try:
sh = None
if not opt.method:
method = "auto"
elif opt.method in [ "auto", "nat", "ipfw" ]:
elif opt.method in [ "auto", "nat", "tproxy", "ipfw" ]:
method = opt.method
else:
o.fatal("method %s not supported"%opt.method)