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 _pidname = None
IP_TRANSPARENT = 19
def check_daemon(pidfile): def check_daemon(pidfile):
global _pidname global _pidname
_pidname = os.path.abspath(pidfile) _pidname = os.path.abspath(pidfile)
@ -232,8 +233,11 @@ def onaccept_tcp(listener, method, mux, handlers):
return return
else: else:
raise raise
dstip = original_dst(sock) if method == "tproxy":
debug1('Accept: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1], dstip = sock.getsockname();
else:
dstip = original_dst(sock)
debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
dstip[0],dstip[1])) dstip[0],dstip[1]))
if dstip[1] == listener.getsockname()[1] and islocal(dstip[0], sock.family): if dstip[1] == listener.getsockname()[1] and islocal(dstip[0], sock.family):
debug1("-- ignored: that's my address!\n") 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) 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: try:
return _main(tcp_listener, fw, ssh_cmd, remotename, return _main(tcp_listener, fw, ssh_cmd, remotename,
python, latency_control, dns_listener, python, latency_control, dns_listener,

View File

@ -118,6 +118,67 @@ def do_iptables_nat(port, dnsport, family, subnets):
'--to-ports', str(dnsport)) '--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): def ipfw_rule_exists(n):
argv = ['ipfw', 'list'] argv = ['ipfw', 'list']
p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE) p = ssubprocess.Popen(argv, stdout = ssubprocess.PIPE)
@ -408,6 +469,8 @@ def main(port_v4, dnsport_v4, method, syslog):
if method == "nat": if method == "nat":
do_it = do_iptables_nat do_it = do_iptables_nat
elif method == "tproxy":
do_it = do_iptables_tproxy
elif method == "ipfw": elif method == "ipfw":
do_it = do_ipfw do_it = do_ipfw
else: 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 H,auto-hosts scan for remote hostnames and update local /etc/hosts
N,auto-nets automatically determine subnets to route N,auto-nets automatically determine subnets to route
dns capture local DNS requests and forward to the remote DNS server 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 python= path to python interpreter on the remote server
r,remote= ssh hostname (and optional username) of remote sshuttle server r,remote= ssh hostname (and optional username) of remote sshuttle server
x,exclude= exclude this subnet (can be used more than once) x,exclude= exclude this subnet (can be used more than once)
@ -120,7 +120,7 @@ try:
sh = None sh = None
if not opt.method: if not opt.method:
method = "auto" method = "auto"
elif opt.method in [ "auto", "nat", "ipfw" ]: elif opt.method in [ "auto", "nat", "tproxy", "ipfw" ]:
method = opt.method method = opt.method
else: else:
o.fatal("method %s not supported"%opt.method) o.fatal("method %s not supported"%opt.method)