Commit f41c6b62 authored by Brian May's avatar Brian May

TProxy support as well as NAT support.

parent 9a7412c0
...@@ -12,6 +12,7 @@ def got_signal(signum, frame): ...@@ -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): ...@@ -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, ...@@ -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,
......
...@@ -118,6 +118,67 @@ def do_iptables_nat(port, dnsport, family, subnets): ...@@ -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): ...@@ -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:
......
...@@ -60,7 +60,7 @@ l,listen= transproxy to this ip address and port number [127.0.0.1:0] ...@@ -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: ...@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment