mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-07-04 16:50:34 +02:00
Compare commits
24 Commits
sshuttle-0
...
sshuttle-0
Author | SHA1 | Date | |
---|---|---|---|
4fde980f46 | |||
621997b279 | |||
ca7d38dc1a | |||
a81972b2b5 | |||
a238f7636c | |||
62e1ac4b46 | |||
f2297066e7 | |||
0bf0351d9b | |||
9731680d2e | |||
88937e148e | |||
7f3c522c56 | |||
ebfc3703ec | |||
760740e9aa | |||
b570778894 | |||
4c5185dc55 | |||
a2fcb08a2d | |||
e7a19890aa | |||
d9b1bb52e5 | |||
a30c4d7ccb | |||
9877a8d6fb | |||
8fde1155da | |||
fdb7c9b995 | |||
675f19f57e | |||
049a0c40ac |
85
client.py
85
client.py
@ -1,4 +1,4 @@
|
|||||||
import struct, socket, select, errno, re, signal
|
import struct, socket, select, errno, re, signal, time
|
||||||
import compat.ssubprocess as ssubprocess
|
import compat.ssubprocess as ssubprocess
|
||||||
import helpers, ssnet, ssh, ssyslog
|
import helpers, ssnet, ssh, ssyslog
|
||||||
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
|
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
|
||||||
@ -6,21 +6,6 @@ from helpers import *
|
|||||||
|
|
||||||
_extra_fd = os.open('/dev/null', os.O_RDONLY)
|
_extra_fd = os.open('/dev/null', os.O_RDONLY)
|
||||||
|
|
||||||
def _islocal(ip):
|
|
||||||
sock = socket.socket()
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
sock.bind((ip, 0))
|
|
||||||
except socket.error, e:
|
|
||||||
if e.args[0] == errno.EADDRNOTAVAIL:
|
|
||||||
return False # not a local IP
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
finally:
|
|
||||||
sock.close()
|
|
||||||
return True # it's a local IP, or there would have been an error
|
|
||||||
|
|
||||||
|
|
||||||
def got_signal(signum, frame):
|
def got_signal(signum, frame):
|
||||||
log('exiting on signal %d\n' % signum)
|
log('exiting on signal %d\n' % signum)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -111,14 +96,15 @@ def original_dst(sock):
|
|||||||
|
|
||||||
|
|
||||||
class FirewallClient:
|
class FirewallClient:
|
||||||
def __init__(self, port, subnets_include, subnets_exclude):
|
def __init__(self, port, subnets_include, subnets_exclude, dnsport):
|
||||||
self.port = port
|
self.port = port
|
||||||
self.auto_nets = []
|
self.auto_nets = []
|
||||||
self.subnets_include = subnets_include
|
self.subnets_include = subnets_include
|
||||||
self.subnets_exclude = subnets_exclude
|
self.subnets_exclude = subnets_exclude
|
||||||
|
self.dnsport = dnsport
|
||||||
argvbase = ([sys.argv[0]] +
|
argvbase = ([sys.argv[0]] +
|
||||||
['-v'] * (helpers.verbose or 0) +
|
['-v'] * (helpers.verbose or 0) +
|
||||||
['--firewall', str(port)])
|
['--firewall', str(port), str(dnsport)])
|
||||||
if ssyslog._p:
|
if ssyslog._p:
|
||||||
argvbase += ['--syslog']
|
argvbase += ['--syslog']
|
||||||
argv_tries = [
|
argv_tries = [
|
||||||
@ -189,7 +175,8 @@ class FirewallClient:
|
|||||||
raise Fatal('cleanup: %r returned %d' % (self.argv, rv))
|
raise Fatal('cleanup: %r returned %d' % (self.argv, rv))
|
||||||
|
|
||||||
|
|
||||||
def _main(listener, fw, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
|
||||||
|
dnslistener, seed_hosts, auto_nets,
|
||||||
syslog, daemon):
|
syslog, daemon):
|
||||||
handlers = []
|
handlers = []
|
||||||
if helpers.verbose >= 1:
|
if helpers.verbose >= 1:
|
||||||
@ -200,7 +187,8 @@ def _main(listener, fw, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
(serverproc, serversock) = ssh.connect(ssh_cmd, remotename, python,
|
(serverproc, serversock) = ssh.connect(ssh_cmd, remotename, python,
|
||||||
stderr=ssyslog._p and ssyslog._p.stdin)
|
stderr=ssyslog._p and ssyslog._p.stdin,
|
||||||
|
options=dict(latency_control=latency_control))
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
if e.args[0] == errno.EPIPE:
|
if e.args[0] == errno.EPIPE:
|
||||||
raise Fatal("failed to establish ssh session (1)")
|
raise Fatal("failed to establish ssh session (1)")
|
||||||
@ -280,16 +268,44 @@ def _main(listener, fw, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
|||||||
dstip = original_dst(sock)
|
dstip = original_dst(sock)
|
||||||
debug1('Accept: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
|
debug1('Accept: %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]):
|
if dstip[1] == listener.getsockname()[1] and islocal(dstip[0]):
|
||||||
debug1("-- ignored: that's my address!\n")
|
debug1("-- ignored: that's my address!\n")
|
||||||
sock.close()
|
sock.close()
|
||||||
return
|
return
|
||||||
chan = mux.next_channel()
|
chan = mux.next_channel()
|
||||||
|
if not chan:
|
||||||
|
log('warning: too many open channels. Discarded connection.\n')
|
||||||
|
sock.close()
|
||||||
|
return
|
||||||
mux.send(chan, ssnet.CMD_CONNECT, '%s,%s' % dstip)
|
mux.send(chan, ssnet.CMD_CONNECT, '%s,%s' % dstip)
|
||||||
outwrap = MuxWrapper(mux, chan)
|
outwrap = MuxWrapper(mux, chan)
|
||||||
handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
|
handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
|
||||||
handlers.append(Handler([listener], onaccept))
|
handlers.append(Handler([listener], onaccept))
|
||||||
|
|
||||||
|
dnsreqs = {}
|
||||||
|
def dns_done(chan, data):
|
||||||
|
peer,timeout = dnsreqs.get(chan) or (None,None)
|
||||||
|
debug3('dns_done: channel=%r peer=%r\n' % (chan, peer))
|
||||||
|
if peer:
|
||||||
|
del dnsreqs[chan]
|
||||||
|
debug3('doing sendto %r\n' % (peer,))
|
||||||
|
dnslistener.sendto(data, peer)
|
||||||
|
def ondns():
|
||||||
|
pkt,peer = dnslistener.recvfrom(4096)
|
||||||
|
now = time.time()
|
||||||
|
if pkt:
|
||||||
|
debug1('DNS request from %r: %d bytes\n' % (peer, len(pkt)))
|
||||||
|
chan = mux.next_channel()
|
||||||
|
dnsreqs[chan] = peer,now+30
|
||||||
|
mux.send(chan, ssnet.CMD_DNS_REQ, pkt)
|
||||||
|
mux.channels[chan] = lambda cmd,data: dns_done(chan,data)
|
||||||
|
for chan,(peer,timeout) in dnsreqs.items():
|
||||||
|
if timeout < now:
|
||||||
|
del dnsreqs[chan]
|
||||||
|
debug3('Remaining DNS requests: %d\n' % len(dnsreqs))
|
||||||
|
if dnslistener:
|
||||||
|
handlers.append(Handler([dnslistener], ondns))
|
||||||
|
|
||||||
if seed_hosts != None:
|
if seed_hosts != None:
|
||||||
debug1('seed_hosts: %r\n' % seed_hosts)
|
debug1('seed_hosts: %r\n' % seed_hosts)
|
||||||
mux.send(0, ssnet.CMD_HOST_REQ, '\n'.join(seed_hosts))
|
mux.send(0, ssnet.CMD_HOST_REQ, '\n'.join(seed_hosts))
|
||||||
@ -300,11 +316,13 @@ def _main(listener, fw, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
|||||||
raise Fatal('server died with error code %d' % rv)
|
raise Fatal('server died with error code %d' % rv)
|
||||||
|
|
||||||
ssnet.runonce(handlers, mux)
|
ssnet.runonce(handlers, mux)
|
||||||
mux.callback()
|
if latency_control:
|
||||||
mux.check_fullness()
|
mux.check_fullness()
|
||||||
|
mux.callback()
|
||||||
|
|
||||||
|
|
||||||
def main(listenip, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
def main(listenip, ssh_cmd, remotename, python, latency_control, dns,
|
||||||
|
seed_hosts, auto_nets,
|
||||||
subnets_include, subnets_exclude, syslog, daemon, pidfile):
|
subnets_include, subnets_exclude, syslog, daemon, pidfile):
|
||||||
if syslog:
|
if syslog:
|
||||||
ssyslog.start_syslog()
|
ssyslog.start_syslog()
|
||||||
@ -315,8 +333,7 @@ def main(listenip, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
|||||||
log("%s\n" % e)
|
log("%s\n" % e)
|
||||||
return 5
|
return 5
|
||||||
debug1('Starting sshuttle proxy.\n')
|
debug1('Starting sshuttle proxy.\n')
|
||||||
listener = socket.socket()
|
|
||||||
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
if listenip[1]:
|
if listenip[1]:
|
||||||
ports = [listenip[1]]
|
ports = [listenip[1]]
|
||||||
else:
|
else:
|
||||||
@ -326,8 +343,13 @@ def main(listenip, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
|||||||
debug2('Binding:')
|
debug2('Binding:')
|
||||||
for port in ports:
|
for port in ports:
|
||||||
debug2(' %d' % port)
|
debug2(' %d' % port)
|
||||||
|
listener = socket.socket()
|
||||||
|
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
dnslistener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
dnslistener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
try:
|
try:
|
||||||
listener.bind((listenip[0], port))
|
listener.bind((listenip[0], port))
|
||||||
|
dnslistener.bind((listenip[0], port))
|
||||||
bound = True
|
bound = True
|
||||||
break
|
break
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
@ -340,11 +362,20 @@ def main(listenip, ssh_cmd, remotename, python, seed_hosts, auto_nets,
|
|||||||
listenip = listener.getsockname()
|
listenip = listener.getsockname()
|
||||||
debug1('Listening on %r.\n' % (listenip,))
|
debug1('Listening on %r.\n' % (listenip,))
|
||||||
|
|
||||||
fw = FirewallClient(listenip[1], subnets_include, subnets_exclude)
|
if dns:
|
||||||
|
dnsip = dnslistener.getsockname()
|
||||||
|
debug1('DNS listening on %r.\n' % (dnsip,))
|
||||||
|
dnsport = dnsip[1]
|
||||||
|
else:
|
||||||
|
dnsport = 0
|
||||||
|
dnslistener = None
|
||||||
|
|
||||||
|
fw = FirewallClient(listenip[1], subnets_include, subnets_exclude, dnsport)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return _main(listener, fw, ssh_cmd, remotename,
|
return _main(listener, fw, ssh_cmd, remotename,
|
||||||
python, seed_hosts, auto_nets, syslog, daemon)
|
python, latency_control, dnslistener,
|
||||||
|
seed_hosts, auto_nets, syslog, daemon)
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
if daemon:
|
if daemon:
|
||||||
|
171
firewall.py
171
firewall.py
@ -1,8 +1,11 @@
|
|||||||
import re, errno
|
import re, errno, socket, select, struct
|
||||||
import compat.ssubprocess as ssubprocess
|
import compat.ssubprocess as ssubprocess
|
||||||
import helpers, ssyslog
|
import helpers, ssyslog
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
|
# python doesn't have a definition for this
|
||||||
|
IPPROTO_DIVERT = 254
|
||||||
|
|
||||||
|
|
||||||
def ipt_chain_exists(name):
|
def ipt_chain_exists(name):
|
||||||
argv = ['iptables', '-t', 'nat', '-nL']
|
argv = ['iptables', '-t', 'nat', '-nL']
|
||||||
@ -23,12 +26,33 @@ def ipt(*args):
|
|||||||
raise Fatal('%r returned %d' % (argv, rv))
|
raise Fatal('%r returned %d' % (argv, rv))
|
||||||
|
|
||||||
|
|
||||||
|
_no_ttl_module = False
|
||||||
|
def ipt_ttl(*args):
|
||||||
|
global _no_ttl_module
|
||||||
|
if not _no_ttl_module:
|
||||||
|
# we avoid infinite loops by generating server-side connections
|
||||||
|
# with ttl 42. This makes the client side not recapture those
|
||||||
|
# connections, in case client == server.
|
||||||
|
try:
|
||||||
|
argsplus = list(args) + ['-m', 'ttl', '!', '--ttl', '42']
|
||||||
|
ipt(*argsplus)
|
||||||
|
except Fatal:
|
||||||
|
ipt(*args)
|
||||||
|
# we only get here if the non-ttl attempt succeeds
|
||||||
|
log('sshuttle: warning: your iptables is missing '
|
||||||
|
'the ttl module.\n')
|
||||||
|
_no_ttl_module = True
|
||||||
|
else:
|
||||||
|
ipt(*args)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# We name the chain based on the transproxy port number so that it's possible
|
# We name the chain based on the transproxy port number so that it's possible
|
||||||
# to run multiple copies of sshuttle at the same time. Of course, the
|
# to run multiple copies of sshuttle at the same time. Of course, the
|
||||||
# multiple copies shouldn't have overlapping subnets, or only the most-
|
# multiple copies shouldn't have overlapping subnets, or only the most-
|
||||||
# recently-started one will win (because we use "-I OUTPUT 1" instead of
|
# recently-started one will win (because we use "-I OUTPUT 1" instead of
|
||||||
# "-A OUTPUT").
|
# "-A OUTPUT").
|
||||||
def do_iptables(port, subnets):
|
def do_iptables(port, dnsport, subnets):
|
||||||
chain = 'sshuttle-%s' % port
|
chain = 'sshuttle-%s' % port
|
||||||
|
|
||||||
# basic cleanup/setup of chains
|
# basic cleanup/setup of chains
|
||||||
@ -38,12 +62,13 @@ def do_iptables(port, subnets):
|
|||||||
ipt('-F', chain)
|
ipt('-F', chain)
|
||||||
ipt('-X', chain)
|
ipt('-X', chain)
|
||||||
|
|
||||||
if subnets:
|
if subnets or dnsport:
|
||||||
ipt('-N', chain)
|
ipt('-N', chain)
|
||||||
ipt('-F', chain)
|
ipt('-F', chain)
|
||||||
ipt('-I', 'OUTPUT', '1', '-j', chain)
|
ipt('-I', 'OUTPUT', '1', '-j', chain)
|
||||||
ipt('-I', 'PREROUTING', '1', '-j', chain)
|
ipt('-I', 'PREROUTING', '1', '-j', chain)
|
||||||
|
|
||||||
|
if subnets:
|
||||||
# create new subnet entries. Note that we're sorting in a very
|
# create new subnet entries. Note that we're sorting in a very
|
||||||
# particular order: we need to go from most-specific (largest swidth)
|
# particular order: we need to go from most-specific (largest swidth)
|
||||||
# to least-specific, and at any given level of specificity, we want
|
# to least-specific, and at any given level of specificity, we want
|
||||||
@ -55,12 +80,19 @@ def do_iptables(port, subnets):
|
|||||||
'--dest', '%s/%s' % (snet,swidth),
|
'--dest', '%s/%s' % (snet,swidth),
|
||||||
'-p', 'tcp')
|
'-p', 'tcp')
|
||||||
else:
|
else:
|
||||||
ipt('-A', chain, '-j', 'REDIRECT',
|
ipt_ttl('-A', chain, '-j', 'REDIRECT',
|
||||||
'--dest', '%s/%s' % (snet,swidth),
|
'--dest', '%s/%s' % (snet,swidth),
|
||||||
'-p', 'tcp',
|
'-p', 'tcp',
|
||||||
'--to-ports', str(port),
|
'--to-ports', str(port))
|
||||||
'-m', 'ttl', '!', '--ttl', '42' # to prevent infinite loops
|
|
||||||
)
|
if dnsport:
|
||||||
|
nslist = resolvconf_nameservers()
|
||||||
|
for ip in nslist:
|
||||||
|
ipt_ttl('-A', chain, '-j', 'REDIRECT',
|
||||||
|
'--dest', '%s/32' % ip,
|
||||||
|
'-p', 'udp',
|
||||||
|
'--dport', '53',
|
||||||
|
'--to-ports', str(dnsport))
|
||||||
|
|
||||||
|
|
||||||
def ipfw_rule_exists(n):
|
def ipfw_rule_exists(n):
|
||||||
@ -69,7 +101,7 @@ def ipfw_rule_exists(n):
|
|||||||
found = False
|
found = False
|
||||||
for line in p.stdout:
|
for line in p.stdout:
|
||||||
if line.startswith('%05d ' % n):
|
if line.startswith('%05d ' % n):
|
||||||
if not ('ipttl 42 setup keep-state' in line
|
if not ('ipttl 42' in line
|
||||||
or ('skipto %d' % (n+1)) in line
|
or ('skipto %d' % (n+1)) in line
|
||||||
or 'check-state' in line):
|
or 'check-state' in line):
|
||||||
log('non-sshuttle ipfw rule: %r\n' % line.strip())
|
log('non-sshuttle ipfw rule: %r\n' % line.strip())
|
||||||
@ -99,11 +131,11 @@ def _fill_oldctls(prefix):
|
|||||||
def _sysctl_set(name, val):
|
def _sysctl_set(name, val):
|
||||||
argv = ['sysctl', '-w', '%s=%s' % (name, val)]
|
argv = ['sysctl', '-w', '%s=%s' % (name, val)]
|
||||||
debug1('>> %s\n' % ' '.join(argv))
|
debug1('>> %s\n' % ' '.join(argv))
|
||||||
rv = ssubprocess.call(argv, stdout = open('/dev/null', 'w'))
|
return ssubprocess.call(argv, stdout = open('/dev/null', 'w'))
|
||||||
|
|
||||||
|
|
||||||
_changedctls = []
|
_changedctls = []
|
||||||
def sysctl_set(name, val):
|
def sysctl_set(name, val, permanent=False):
|
||||||
PREFIX = 'net.inet.ip'
|
PREFIX = 'net.inet.ip'
|
||||||
assert(name.startswith(PREFIX + '.'))
|
assert(name.startswith(PREFIX + '.'))
|
||||||
val = str(val)
|
val = str(val)
|
||||||
@ -114,8 +146,49 @@ def sysctl_set(name, val):
|
|||||||
return
|
return
|
||||||
oldval = _oldctls[name]
|
oldval = _oldctls[name]
|
||||||
if val != oldval:
|
if val != oldval:
|
||||||
|
rv = _sysctl_set(name, val)
|
||||||
|
if rv==0 and permanent:
|
||||||
|
debug1('>> ...saving permanently in /etc/sysctl.conf\n')
|
||||||
|
f = open('/etc/sysctl.conf', 'a')
|
||||||
|
f.write('\n'
|
||||||
|
'# Added by sshuttle\n'
|
||||||
|
'%s=%s\n' % (name, val))
|
||||||
|
f.close()
|
||||||
|
else:
|
||||||
_changedctls.append(name)
|
_changedctls.append(name)
|
||||||
return _sysctl_set(name, val)
|
|
||||||
|
|
||||||
|
def _udp_unpack(p):
|
||||||
|
src = (socket.inet_ntoa(p[12:16]), struct.unpack('!H', p[20:22])[0])
|
||||||
|
dst = (socket.inet_ntoa(p[16:20]), struct.unpack('!H', p[22:24])[0])
|
||||||
|
return src, dst
|
||||||
|
|
||||||
|
|
||||||
|
def _udp_repack(p, src, dst):
|
||||||
|
addrs = socket.inet_aton(src[0]) + socket.inet_aton(dst[0])
|
||||||
|
ports = struct.pack('!HH', src[1], dst[1])
|
||||||
|
return p[:12] + addrs + ports + p[24:]
|
||||||
|
|
||||||
|
|
||||||
|
_real_dns_server = [None]
|
||||||
|
def _handle_diversion(divertsock, dnsport):
|
||||||
|
p,tag = divertsock.recvfrom(4096)
|
||||||
|
src,dst = _udp_unpack(p)
|
||||||
|
debug3('got diverted packet from %r to %r\n' % (src, dst))
|
||||||
|
if dst[1] == 53:
|
||||||
|
# outgoing DNS
|
||||||
|
debug3('...packet is a DNS request.\n')
|
||||||
|
_real_dns_server[0] = dst
|
||||||
|
dst = ('127.0.0.1', dnsport)
|
||||||
|
elif src[1] == dnsport:
|
||||||
|
if islocal(src[0]):
|
||||||
|
debug3('...packet is a DNS response.\n')
|
||||||
|
src = _real_dns_server[0]
|
||||||
|
else:
|
||||||
|
log('weird?! unexpected divert from %r to %r\n' % (src, dst))
|
||||||
|
assert(0)
|
||||||
|
newp = _udp_repack(p, src, dst)
|
||||||
|
divertsock.sendto(newp, tag)
|
||||||
|
|
||||||
|
|
||||||
def ipfw(*args):
|
def ipfw(*args):
|
||||||
@ -126,7 +199,7 @@ def ipfw(*args):
|
|||||||
raise Fatal('%r returned %d' % (argv, rv))
|
raise Fatal('%r returned %d' % (argv, rv))
|
||||||
|
|
||||||
|
|
||||||
def do_ipfw(port, subnets):
|
def do_ipfw(port, dnsport, subnets):
|
||||||
sport = str(port)
|
sport = str(port)
|
||||||
xsport = str(port+1)
|
xsport = str(port+1)
|
||||||
|
|
||||||
@ -139,13 +212,14 @@ def do_ipfw(port, subnets):
|
|||||||
oldval = _oldctls[name]
|
oldval = _oldctls[name]
|
||||||
_sysctl_set(name, oldval)
|
_sysctl_set(name, oldval)
|
||||||
|
|
||||||
if subnets:
|
if subnets or dnsport:
|
||||||
sysctl_set('net.inet.ip.fw.enable', 1)
|
sysctl_set('net.inet.ip.fw.enable', 1)
|
||||||
sysctl_set('net.inet.ip.scopedroute', 0)
|
sysctl_set('net.inet.ip.scopedroute', 0, permanent=True)
|
||||||
|
|
||||||
ipfw('add', sport, 'check-state', 'ip',
|
ipfw('add', sport, 'check-state', 'ip',
|
||||||
'from', 'any', 'to', 'any')
|
'from', 'any', 'to', 'any')
|
||||||
|
|
||||||
|
if subnets:
|
||||||
# create new subnet entries
|
# create new subnet entries
|
||||||
for swidth,sexclude,snet in sorted(subnets, reverse=True):
|
for swidth,sexclude,snet in sorted(subnets, reverse=True):
|
||||||
if sexclude:
|
if sexclude:
|
||||||
@ -158,6 +232,65 @@ def do_ipfw(port, subnets):
|
|||||||
'from', 'any', 'to', '%s/%s' % (snet,swidth),
|
'from', 'any', 'to', '%s/%s' % (snet,swidth),
|
||||||
'not', 'ipttl', '42', 'keep-state', 'setup')
|
'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 ip in nslist:
|
||||||
|
# relabel and then catch outgoing DNS requests
|
||||||
|
ipfw('add', sport, 'divert', sport,
|
||||||
|
'log', 'udp',
|
||||||
|
'from', 'any', 'to', '%s/32' % ip, '53',
|
||||||
|
'not', 'ipttl', '42')
|
||||||
|
# relabel DNS responses
|
||||||
|
ipfw('add', sport, 'divert', sport,
|
||||||
|
'log', '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
|
||||||
|
|
||||||
|
|
||||||
def program_exists(name):
|
def program_exists(name):
|
||||||
paths = (os.getenv('PATH') or os.defpath).split(os.pathsep)
|
paths = (os.getenv('PATH') or os.defpath).split(os.pathsep)
|
||||||
@ -166,6 +299,7 @@ def program_exists(name):
|
|||||||
if os.path.exists(fn):
|
if os.path.exists(fn):
|
||||||
return not os.path.isdir(fn) and os.access(fn, os.X_OK)
|
return not os.path.isdir(fn) and os.access(fn, os.X_OK)
|
||||||
|
|
||||||
|
|
||||||
hostmap = {}
|
hostmap = {}
|
||||||
def rewrite_etc_hosts(port):
|
def rewrite_etc_hosts(port):
|
||||||
HOSTSFILE='/etc/hosts'
|
HOSTSFILE='/etc/hosts'
|
||||||
@ -216,9 +350,11 @@ def restore_etc_hosts(port):
|
|||||||
# exit. In case that fails, it's not the end of the world; future runs will
|
# exit. In case that fails, it's not the end of the world; future runs will
|
||||||
# supercede it in the transproxy list, at least, so the leftover rules
|
# supercede it in the transproxy list, at least, so the leftover rules
|
||||||
# are hopefully harmless.
|
# are hopefully harmless.
|
||||||
def main(port, syslog):
|
def main(port, dnsport, syslog):
|
||||||
assert(port > 0)
|
assert(port > 0)
|
||||||
assert(port <= 65535)
|
assert(port <= 65535)
|
||||||
|
assert(dnsport >= 0)
|
||||||
|
assert(dnsport <= 65535)
|
||||||
|
|
||||||
if os.getuid() != 0:
|
if os.getuid() != 0:
|
||||||
raise Fatal('you must be root (or enable su/sudo) to set the firewall')
|
raise Fatal('you must be root (or enable su/sudo) to set the firewall')
|
||||||
@ -272,7 +408,7 @@ def main(port, syslog):
|
|||||||
try:
|
try:
|
||||||
if line:
|
if line:
|
||||||
debug1('firewall manager: starting transproxy.\n')
|
debug1('firewall manager: starting transproxy.\n')
|
||||||
do_it(port, subnets)
|
do_wait = do_it(port, dnsport, subnets)
|
||||||
sys.stdout.write('STARTED\n')
|
sys.stdout.write('STARTED\n')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -286,6 +422,7 @@ def main(port, syslog):
|
|||||||
# to stay running so that we don't need a *second* password
|
# to stay running so that we don't need a *second* password
|
||||||
# authentication at shutdown time - that cleanup is important!
|
# authentication at shutdown time - that cleanup is important!
|
||||||
while 1:
|
while 1:
|
||||||
|
if do_wait: do_wait()
|
||||||
line = sys.stdin.readline(128)
|
line = sys.stdin.readline(128)
|
||||||
if line.startswith('HOST '):
|
if line.startswith('HOST '):
|
||||||
(name,ip) = line[5:].strip().split(',', 1)
|
(name,ip) = line[5:].strip().split(',', 1)
|
||||||
@ -300,5 +437,5 @@ def main(port, syslog):
|
|||||||
debug1('firewall manager: undoing changes.\n')
|
debug1('firewall manager: undoing changes.\n')
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
do_it(port, [])
|
do_it(port, 0, [])
|
||||||
restore_etc_hosts(port)
|
restore_etc_hosts(port)
|
||||||
|
40
helpers.py
40
helpers.py
@ -1,4 +1,4 @@
|
|||||||
import sys, os
|
import sys, os, socket
|
||||||
|
|
||||||
logprefix = ''
|
logprefix = ''
|
||||||
verbose = 0
|
verbose = 0
|
||||||
@ -35,3 +35,41 @@ def list_contains_any(l, sub):
|
|||||||
if i in l:
|
if i in l:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def resolvconf_nameservers():
|
||||||
|
l = []
|
||||||
|
for line in open('/etc/resolv.conf'):
|
||||||
|
words = line.lower().split()
|
||||||
|
if len(words) >= 2 and words[0] == 'nameserver':
|
||||||
|
l.append(words[1])
|
||||||
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
def resolvconf_random_nameserver():
|
||||||
|
l = resolvconf_nameservers()
|
||||||
|
if l:
|
||||||
|
if len(l) > 1:
|
||||||
|
# don't import this unless we really need it
|
||||||
|
import random
|
||||||
|
random.shuffle(l)
|
||||||
|
return l[0]
|
||||||
|
else:
|
||||||
|
return '127.0.0.1'
|
||||||
|
|
||||||
|
|
||||||
|
def islocal(ip):
|
||||||
|
sock = socket.socket()
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
sock.bind((ip, 0))
|
||||||
|
except socket.error, e:
|
||||||
|
if e.args[0] == errno.EADDRNOTAVAIL:
|
||||||
|
return False # not a local IP
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
sock.close()
|
||||||
|
return True # it's a local IP, or there would have been an error
|
||||||
|
|
||||||
|
|
||||||
|
17
main.py
17
main.py
@ -54,12 +54,15 @@ sshuttle --hostwatch
|
|||||||
l,listen= transproxy to this ip address and port number [127.0.0.1:0]
|
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
|
||||||
python= path to python interpreter on the remote server [python]
|
python= path to python interpreter on the remote server [python]
|
||||||
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)
|
||||||
v,verbose increase debug message verbosity
|
v,verbose increase debug message verbosity
|
||||||
e,ssh-cmd= the command to use to connect to the remote [ssh]
|
e,ssh-cmd= the command to use to connect to the remote [ssh]
|
||||||
seed-hosts= with -H, use these hostnames for initial scan (comma-separated)
|
seed-hosts= with -H, use these hostnames for initial scan (comma-separated)
|
||||||
|
no-latency-control sacrifice latency to improve bandwidth benchmarks
|
||||||
|
wrap= restart counting channel numbers after this number (for testing)
|
||||||
D,daemon run in the background as a daemon
|
D,daemon run in the background as a daemon
|
||||||
syslog send log messages to syslog (default if you use --daemon)
|
syslog send log messages to syslog (default if you use --daemon)
|
||||||
pidfile= pidfile name (only if using --daemon) [./sshuttle.pid]
|
pidfile= pidfile name (only if using --daemon) [./sshuttle.pid]
|
||||||
@ -67,22 +70,26 @@ server (internal use only)
|
|||||||
firewall (internal use only)
|
firewall (internal use only)
|
||||||
hostwatch (internal use only)
|
hostwatch (internal use only)
|
||||||
"""
|
"""
|
||||||
o = options.Options('sshuttle', optspec)
|
o = options.Options(optspec)
|
||||||
(opt, flags, extra) = o.parse(sys.argv[1:])
|
(opt, flags, extra) = o.parse(sys.argv[1:])
|
||||||
|
|
||||||
if opt.daemon:
|
if opt.daemon:
|
||||||
opt.syslog = 1
|
opt.syslog = 1
|
||||||
|
if opt.wrap:
|
||||||
|
import ssnet
|
||||||
|
ssnet.MAX_CHANNEL = int(opt.wrap)
|
||||||
helpers.verbose = opt.verbose
|
helpers.verbose = opt.verbose
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if opt.server:
|
if opt.server:
|
||||||
if len(extra) != 0:
|
if len(extra) != 0:
|
||||||
o.fatal('no arguments expected')
|
o.fatal('no arguments expected')
|
||||||
|
server.latency_control = opt.latency_control
|
||||||
sys.exit(server.main())
|
sys.exit(server.main())
|
||||||
elif opt.firewall:
|
elif opt.firewall:
|
||||||
if len(extra) != 1:
|
if len(extra) != 2:
|
||||||
o.fatal('exactly one argument expected')
|
o.fatal('exactly two arguments expected')
|
||||||
sys.exit(firewall.main(int(extra[0]), opt.syslog))
|
sys.exit(firewall.main(int(extra[0]), int(extra[1]), opt.syslog))
|
||||||
elif opt.hostwatch:
|
elif opt.hostwatch:
|
||||||
sys.exit(hostwatch.hw_main(extra))
|
sys.exit(hostwatch.hw_main(extra))
|
||||||
else:
|
else:
|
||||||
@ -108,6 +115,8 @@ try:
|
|||||||
opt.ssh_cmd,
|
opt.ssh_cmd,
|
||||||
remotename,
|
remotename,
|
||||||
opt.python,
|
opt.python,
|
||||||
|
opt.latency_control,
|
||||||
|
opt.dns,
|
||||||
sh,
|
sh,
|
||||||
opt.auto_nets,
|
opt.auto_nets,
|
||||||
parse_subnets(includes),
|
parse_subnets(includes),
|
||||||
|
@ -76,9 +76,8 @@ class Options:
|
|||||||
By default, the parser function is getopt.gnu_getopt, and the abort
|
By default, the parser function is getopt.gnu_getopt, and the abort
|
||||||
behaviour is to exit the program.
|
behaviour is to exit the program.
|
||||||
"""
|
"""
|
||||||
def __init__(self, exe, optspec, optfunc=getopt.gnu_getopt,
|
def __init__(self, optspec, optfunc=getopt.gnu_getopt,
|
||||||
onabort=_default_onabort):
|
onabort=_default_onabort):
|
||||||
self.exe = exe
|
|
||||||
self.optspec = optspec
|
self.optspec = optspec
|
||||||
self._onabort = onabort
|
self._onabort = onabort
|
||||||
self.optfunc = optfunc
|
self.optfunc = optfunc
|
||||||
@ -122,8 +121,8 @@ class Options:
|
|||||||
defval = None
|
defval = None
|
||||||
flagl = flags.split(',')
|
flagl = flags.split(',')
|
||||||
flagl_nice = []
|
flagl_nice = []
|
||||||
for f in flagl:
|
for _f in flagl:
|
||||||
f,dvi = _remove_negative_kv(f, _intify(defval))
|
f,dvi = _remove_negative_kv(_f, _intify(defval))
|
||||||
self._aliases[f] = _remove_negative_k(flagl[0])
|
self._aliases[f] = _remove_negative_k(flagl[0])
|
||||||
self._hasparms[f] = has_parm
|
self._hasparms[f] = has_parm
|
||||||
self._defaults[f] = dvi
|
self._defaults[f] = dvi
|
||||||
@ -135,7 +134,7 @@ class Options:
|
|||||||
self._aliases[f_nice] = _remove_negative_k(flagl[0])
|
self._aliases[f_nice] = _remove_negative_k(flagl[0])
|
||||||
self._longopts.append(f + (has_parm and '=' or ''))
|
self._longopts.append(f + (has_parm and '=' or ''))
|
||||||
self._longopts.append('no-' + f)
|
self._longopts.append('no-' + f)
|
||||||
flagl_nice.append('--' + f)
|
flagl_nice.append('--' + _f)
|
||||||
flags_nice = ', '.join(flagl_nice)
|
flags_nice = ', '.join(flagl_nice)
|
||||||
if has_parm:
|
if has_parm:
|
||||||
flags_nice += ' ...'
|
flags_nice += ' ...'
|
||||||
|
38
server.py
38
server.py
@ -1,4 +1,4 @@
|
|||||||
import re, struct, socket, select, traceback
|
import re, struct, socket, select, traceback, time
|
||||||
if not globals().get('skip_imports'):
|
if not globals().get('skip_imports'):
|
||||||
import ssnet, helpers, hostwatch
|
import ssnet, helpers, hostwatch
|
||||||
import compat.ssubprocess as ssubprocess
|
import compat.ssubprocess as ssubprocess
|
||||||
@ -106,11 +106,31 @@ class Hostwatch:
|
|||||||
self.sock = None
|
self.sock = None
|
||||||
|
|
||||||
|
|
||||||
|
class DnsProxy(Handler):
|
||||||
|
def __init__(self, mux, chan, request):
|
||||||
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
Handler.__init__(self, [sock])
|
||||||
|
self.sock = sock
|
||||||
|
self.timeout = time.time()+30
|
||||||
|
self.mux = mux
|
||||||
|
self.chan = chan
|
||||||
|
self.sock.setsockopt(socket.SOL_IP, socket.IP_TTL, 42)
|
||||||
|
self.sock.connect((resolvconf_random_nameserver(), 53))
|
||||||
|
self.sock.send(request)
|
||||||
|
|
||||||
|
def callback(self):
|
||||||
|
data = self.sock.recv(4096)
|
||||||
|
debug2('DNS response: %d bytes\n' % len(data))
|
||||||
|
self.mux.send(self.chan, ssnet.CMD_DNS_RESPONSE, data)
|
||||||
|
self.ok = False
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if helpers.verbose >= 1:
|
if helpers.verbose >= 1:
|
||||||
helpers.logprefix = ' s: '
|
helpers.logprefix = ' s: '
|
||||||
else:
|
else:
|
||||||
helpers.logprefix = 'server: '
|
helpers.logprefix = 'server: '
|
||||||
|
debug1('latency control setting = %r\n' % latency_control)
|
||||||
|
|
||||||
routes = list(list_routes())
|
routes = list(list_routes())
|
||||||
debug1('available routes:\n')
|
debug1('available routes:\n')
|
||||||
@ -164,6 +184,14 @@ def main():
|
|||||||
handlers.append(Proxy(MuxWrapper(mux, channel), outwrap))
|
handlers.append(Proxy(MuxWrapper(mux, channel), outwrap))
|
||||||
mux.new_channel = new_channel
|
mux.new_channel = new_channel
|
||||||
|
|
||||||
|
dnshandlers = {}
|
||||||
|
def dns_req(channel, data):
|
||||||
|
debug2('Incoming DNS request.\n')
|
||||||
|
h = DnsProxy(mux, channel, data)
|
||||||
|
handlers.append(h)
|
||||||
|
dnshandlers[channel] = h
|
||||||
|
mux.got_dns_req = dns_req
|
||||||
|
|
||||||
while mux.ok:
|
while mux.ok:
|
||||||
if hw.pid:
|
if hw.pid:
|
||||||
assert(hw.pid > 0)
|
assert(hw.pid > 0)
|
||||||
@ -172,5 +200,13 @@ def main():
|
|||||||
raise Fatal('hostwatch exited unexpectedly: code 0x%04x\n' % rv)
|
raise Fatal('hostwatch exited unexpectedly: code 0x%04x\n' % rv)
|
||||||
|
|
||||||
ssnet.runonce(handlers, mux)
|
ssnet.runonce(handlers, mux)
|
||||||
|
if latency_control:
|
||||||
mux.check_fullness()
|
mux.check_fullness()
|
||||||
mux.callback()
|
mux.callback()
|
||||||
|
|
||||||
|
if dnshandlers:
|
||||||
|
now = time.time()
|
||||||
|
for channel,h in dnshandlers.items():
|
||||||
|
if h.timeout < now or not h.ok:
|
||||||
|
del dnshandlers[channel]
|
||||||
|
h.ok = False
|
||||||
|
14
ssh.py
14
ssh.py
@ -14,14 +14,16 @@ def readfile(name):
|
|||||||
raise Exception("can't find file %r in any of %r" % (name, path))
|
raise Exception("can't find file %r in any of %r" % (name, path))
|
||||||
|
|
||||||
|
|
||||||
def empackage(z, filename):
|
def empackage(z, filename, data=None):
|
||||||
(path,basename) = os.path.split(filename)
|
(path,basename) = os.path.split(filename)
|
||||||
content = z.compress(readfile(filename))
|
if not data:
|
||||||
|
data = readfile(filename)
|
||||||
|
content = z.compress(data)
|
||||||
content += z.flush(zlib.Z_SYNC_FLUSH)
|
content += z.flush(zlib.Z_SYNC_FLUSH)
|
||||||
return '%s\n%d\n%s' % (basename,len(content), content)
|
return '%s\n%d\n%s' % (basename, len(content), content)
|
||||||
|
|
||||||
|
|
||||||
def connect(ssh_cmd, rhostport, python, stderr):
|
def connect(ssh_cmd, rhostport, python, stderr, options):
|
||||||
main_exe = sys.argv[0]
|
main_exe = sys.argv[0]
|
||||||
portl = []
|
portl = []
|
||||||
|
|
||||||
@ -52,7 +54,9 @@ def connect(ssh_cmd, rhostport, python, stderr):
|
|||||||
|
|
||||||
z = zlib.compressobj(1)
|
z = zlib.compressobj(1)
|
||||||
content = readfile('assembler.py')
|
content = readfile('assembler.py')
|
||||||
content2 = (empackage(z, 'helpers.py') +
|
optdata = ''.join("%s=%r\n" % (k,v) for (k,v) in options.items())
|
||||||
|
content2 = (empackage(z, 'cmdline_options.py', optdata) +
|
||||||
|
empackage(z, 'helpers.py') +
|
||||||
empackage(z, 'compat/ssubprocess.py') +
|
empackage(z, 'compat/ssubprocess.py') +
|
||||||
empackage(z, 'ssnet.py') +
|
empackage(z, 'ssnet.py') +
|
||||||
empackage(z, 'hostwatch.py') +
|
empackage(z, 'hostwatch.py') +
|
||||||
|
20
sshuttle.md
20
sshuttle.md
@ -1,6 +1,6 @@
|
|||||||
% sshuttle(8) Sshuttle 0.44
|
% sshuttle(8) Sshuttle 0.46
|
||||||
% Avery Pennarun <apenwarr@gmail.com>
|
% Avery Pennarun <apenwarr@gmail.com>
|
||||||
% 2010-12-31
|
% 2011-01-25
|
||||||
|
|
||||||
# NAME
|
# NAME
|
||||||
|
|
||||||
@ -109,6 +109,22 @@ entire subnet to the VPN.
|
|||||||
if you use this option to give it a few names to start
|
if you use this option to give it a few names to start
|
||||||
from.
|
from.
|
||||||
|
|
||||||
|
--no-latency-control
|
||||||
|
: sacrifice latency to improve bandwidth benchmarks. ssh
|
||||||
|
uses really big socket buffers, which can overload the
|
||||||
|
connection if you start doing large file transfers,
|
||||||
|
thus making all your other sessions inside the same
|
||||||
|
tunnel go slowly. Normally, sshuttle tries to avoid
|
||||||
|
this problem using a "fullness check" that allows only
|
||||||
|
a certain amount of outstanding data to be buffered at
|
||||||
|
a time. But on high-bandwidth links, this can leave a
|
||||||
|
lot of your bandwidth underutilized. It also makes
|
||||||
|
sshuttle seem slow in bandwidth benchmarks (benchmarks
|
||||||
|
rarely test ping latency, which is what sshuttle is
|
||||||
|
trying to control). This option disables the latency
|
||||||
|
control feature, maximizing bandwidth usage. Use at
|
||||||
|
your own risk.
|
||||||
|
|
||||||
-D, --daemon
|
-D, --daemon
|
||||||
: automatically fork into the background after connecting
|
: automatically fork into the background after connecting
|
||||||
to the remote server. Implies `--syslog`.
|
to the remote server. Implies `--syslog`.
|
||||||
|
14
ssnet.py
14
ssnet.py
@ -2,6 +2,8 @@ import struct, socket, errno, select
|
|||||||
if not globals().get('skip_imports'):
|
if not globals().get('skip_imports'):
|
||||||
from helpers import *
|
from helpers import *
|
||||||
|
|
||||||
|
MAX_CHANNEL = 65535
|
||||||
|
|
||||||
# these don't exist in the socket module in python 2.3!
|
# these don't exist in the socket module in python 2.3!
|
||||||
SHUT_RD = 0
|
SHUT_RD = 0
|
||||||
SHUT_WR = 1
|
SHUT_WR = 1
|
||||||
@ -21,6 +23,8 @@ CMD_DATA = 0x4206
|
|||||||
CMD_ROUTES = 0x4207
|
CMD_ROUTES = 0x4207
|
||||||
CMD_HOST_REQ = 0x4208
|
CMD_HOST_REQ = 0x4208
|
||||||
CMD_HOST_LIST = 0x4209
|
CMD_HOST_LIST = 0x4209
|
||||||
|
CMD_DNS_REQ = 0x420a
|
||||||
|
CMD_DNS_RESPONSE = 0x420b
|
||||||
|
|
||||||
cmd_to_name = {
|
cmd_to_name = {
|
||||||
CMD_EXIT: 'EXIT',
|
CMD_EXIT: 'EXIT',
|
||||||
@ -33,6 +37,8 @@ cmd_to_name = {
|
|||||||
CMD_ROUTES: 'ROUTES',
|
CMD_ROUTES: 'ROUTES',
|
||||||
CMD_HOST_REQ: 'HOST_REQ',
|
CMD_HOST_REQ: 'HOST_REQ',
|
||||||
CMD_HOST_LIST: 'HOST_LIST',
|
CMD_HOST_LIST: 'HOST_LIST',
|
||||||
|
CMD_DNS_REQ: 'DNS_REQ',
|
||||||
|
CMD_DNS_RESPONSE: 'DNS_RESPONSE',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -281,7 +287,7 @@ class Mux(Handler):
|
|||||||
Handler.__init__(self, [rsock, wsock])
|
Handler.__init__(self, [rsock, wsock])
|
||||||
self.rsock = rsock
|
self.rsock = rsock
|
||||||
self.wsock = wsock
|
self.wsock = wsock
|
||||||
self.new_channel = self.got_routes = None
|
self.new_channel = self.got_dns_req = self.got_routes = None
|
||||||
self.got_host_req = self.got_host_list = None
|
self.got_host_req = self.got_host_list = None
|
||||||
self.channels = {}
|
self.channels = {}
|
||||||
self.chani = 0
|
self.chani = 0
|
||||||
@ -296,7 +302,7 @@ class Mux(Handler):
|
|||||||
# channel 0 is special, so we never allocate it
|
# channel 0 is special, so we never allocate it
|
||||||
for timeout in xrange(1024):
|
for timeout in xrange(1024):
|
||||||
self.chani += 1
|
self.chani += 1
|
||||||
if self.chani > 65535:
|
if self.chani > MAX_CHANNEL:
|
||||||
self.chani = 1
|
self.chani = 1
|
||||||
if not self.channels.get(self.chani):
|
if not self.channels.get(self.chani):
|
||||||
return self.chani
|
return self.chani
|
||||||
@ -343,6 +349,10 @@ class Mux(Handler):
|
|||||||
assert(not self.channels.get(channel))
|
assert(not self.channels.get(channel))
|
||||||
if self.new_channel:
|
if self.new_channel:
|
||||||
self.new_channel(channel, data)
|
self.new_channel(channel, data)
|
||||||
|
elif cmd == CMD_DNS_REQ:
|
||||||
|
assert(not self.channels.get(channel))
|
||||||
|
if self.got_dns_req:
|
||||||
|
self.got_dns_req(channel, data)
|
||||||
elif cmd == CMD_ROUTES:
|
elif cmd == CMD_ROUTES:
|
||||||
if self.got_routes:
|
if self.got_routes:
|
||||||
self.got_routes(data)
|
self.got_routes(data)
|
||||||
|
86
stresstest.py
Executable file
86
stresstest.py
Executable file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import sys, os, socket, select, struct, time
|
||||||
|
|
||||||
|
listener = socket.socket()
|
||||||
|
listener.bind(('127.0.0.1', 0))
|
||||||
|
listener.listen(500)
|
||||||
|
|
||||||
|
servers = []
|
||||||
|
clients = []
|
||||||
|
remain = {}
|
||||||
|
|
||||||
|
NUMCLIENTS = 50
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
if len(clients) < NUMCLIENTS:
|
||||||
|
c = socket.socket()
|
||||||
|
c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
c.bind(('0.0.0.0', 0))
|
||||||
|
c.connect(listener.getsockname())
|
||||||
|
count += 1
|
||||||
|
if count >= 16384:
|
||||||
|
count = 1
|
||||||
|
print 'cli CREATING %d' % count
|
||||||
|
b = struct.pack('I', count) + 'x'*count
|
||||||
|
remain[c] = count
|
||||||
|
print 'cli >> %r' % len(b)
|
||||||
|
c.send(b)
|
||||||
|
c.shutdown(socket.SHUT_WR)
|
||||||
|
clients.append(c)
|
||||||
|
r = [listener]
|
||||||
|
time.sleep(0.1)
|
||||||
|
else:
|
||||||
|
r = [listener]+servers+clients
|
||||||
|
print 'select(%d)' % len(r)
|
||||||
|
r,w,x = select.select(r, [], [], 5)
|
||||||
|
assert(r)
|
||||||
|
for i in r:
|
||||||
|
if i == listener:
|
||||||
|
s,addr = listener.accept()
|
||||||
|
servers.append(s)
|
||||||
|
elif i in servers:
|
||||||
|
b = i.recv(4096)
|
||||||
|
print 'srv << %r' % len(b)
|
||||||
|
if not i in remain:
|
||||||
|
assert(len(b) >= 4)
|
||||||
|
want = struct.unpack('I', b[:4])[0]
|
||||||
|
b = b[4:]
|
||||||
|
#i.send('y'*want)
|
||||||
|
else:
|
||||||
|
want = remain[i]
|
||||||
|
if want < len(b):
|
||||||
|
print 'weird wanted %d bytes, got %d: %r' % (want, len(b), b)
|
||||||
|
assert(want >= len(b))
|
||||||
|
want -= len(b)
|
||||||
|
remain[i] = want
|
||||||
|
if not b: # EOF
|
||||||
|
if want:
|
||||||
|
print 'weird: eof but wanted %d more' % want
|
||||||
|
assert(want == 0)
|
||||||
|
i.close()
|
||||||
|
servers.remove(i)
|
||||||
|
del remain[i]
|
||||||
|
else:
|
||||||
|
print 'srv >> %r' % len(b)
|
||||||
|
i.send('y'*len(b))
|
||||||
|
if not want:
|
||||||
|
i.shutdown(socket.SHUT_WR)
|
||||||
|
elif i in clients:
|
||||||
|
b = i.recv(4096)
|
||||||
|
print 'cli << %r' % len(b)
|
||||||
|
want = remain[i]
|
||||||
|
if want < len(b):
|
||||||
|
print 'weird wanted %d bytes, got %d: %r' % (want, len(b), b)
|
||||||
|
assert(want >= len(b))
|
||||||
|
want -= len(b)
|
||||||
|
remain[i] = want
|
||||||
|
if not b: # EOF
|
||||||
|
if want:
|
||||||
|
print 'weird: eof but wanted %d more' % want
|
||||||
|
assert(want == 0)
|
||||||
|
i.close()
|
||||||
|
clients.remove(i)
|
||||||
|
del remain[i]
|
||||||
|
listener.accept()
|
@ -2,17 +2,17 @@
|
|||||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||||
<data>
|
<data>
|
||||||
<int key="IBDocument.SystemTarget">1060</int>
|
<int key="IBDocument.SystemTarget">1060</int>
|
||||||
<string key="IBDocument.SystemVersion">10H574</string>
|
<string key="IBDocument.SystemVersion">10J567</string>
|
||||||
<string key="IBDocument.InterfaceBuilderVersion">762</string>
|
<string key="IBDocument.InterfaceBuilderVersion">762</string>
|
||||||
<string key="IBDocument.AppKitVersion">1038.35</string>
|
<string key="IBDocument.AppKitVersion">1038.35</string>
|
||||||
<string key="IBDocument.HIToolboxVersion">461.00</string>
|
<string key="IBDocument.HIToolboxVersion">462.00</string>
|
||||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string key="NS.object.0">762</string>
|
<string key="NS.object.0">762</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<integer value="233"/>
|
<integer value="237"/>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
@ -41,9 +41,9 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="411825121">
|
<object class="NSWindowTemplate" id="411825121">
|
||||||
<int key="NSWindowStyleMask">3</int>
|
<int key="NSWindowStyleMask">11</int>
|
||||||
<int key="NSWindowBacking">2</int>
|
<int key="NSWindowBacking">2</int>
|
||||||
<string key="NSWindowRect">{{157, 116}, {611, 369}}</string>
|
<string key="NSWindowRect">{{324, 171}, {611, 469}}</string>
|
||||||
<int key="NSWTFlags">1886913536</int>
|
<int key="NSWTFlags">1886913536</int>
|
||||||
<string key="NSWindowTitle">Sshuttle VPN Preferences</string>
|
<string key="NSWindowTitle">Sshuttle VPN Preferences</string>
|
||||||
<string key="NSWindowClass">NSWindow</string>
|
<string key="NSWindowClass">NSWindow</string>
|
||||||
@ -51,16 +51,16 @@
|
|||||||
<characters key="NS.bytes">View</characters>
|
<characters key="NS.bytes">View</characters>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
<string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||||
<string key="NSWindowContentMinSize">{213, 107}</string>
|
<string key="NSWindowContentMinSize">{611, 469}</string>
|
||||||
<object class="NSView" key="NSWindowView" id="174067038">
|
<object class="NSView" key="NSWindowView" id="174067038">
|
||||||
<reference key="NSNextResponder"/>
|
<reference key="NSNextResponder"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">274</int>
|
||||||
<object class="NSMutableArray" key="NSSubviews">
|
<object class="NSMutableArray" key="NSSubviews">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSTabView" id="389252804">
|
<object class="NSTabView" id="389252804">
|
||||||
<reference key="NSNextResponder" ref="174067038"/>
|
<reference key="NSNextResponder" ref="174067038"/>
|
||||||
<int key="NSvFlags">12</int>
|
<int key="NSvFlags">18</int>
|
||||||
<string key="NSFrame">{{-8, -10}, {627, 373}}</string>
|
<string key="NSFrame">{{-8, -10}, {627, 473}}</string>
|
||||||
<reference key="NSSuperview" ref="174067038"/>
|
<reference key="NSSuperview" ref="174067038"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<object class="NSMutableArray" key="NSTabViewItems">
|
<object class="NSMutableArray" key="NSTabViewItems">
|
||||||
@ -68,13 +68,13 @@
|
|||||||
<object class="NSTabViewItem" id="762265164">
|
<object class="NSTabViewItem" id="762265164">
|
||||||
<string key="NSIdentifier">1</string>
|
<string key="NSIdentifier">1</string>
|
||||||
<object class="NSView" key="NSView" id="60314308">
|
<object class="NSView" key="NSView" id="60314308">
|
||||||
<nil key="NSNextResponder"/>
|
<reference key="NSNextResponder" ref="389252804"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">274</int>
|
||||||
<object class="NSMutableArray" key="NSSubviews">
|
<object class="NSMutableArray" key="NSSubviews">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSButton" id="26015719">
|
<object class="NSButton" id="26015719">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">292</int>
|
||||||
<string key="NSFrame">{{17, 17}, {25, 23}}</string>
|
<string key="NSFrame">{{17, 17}, {25, 23}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -103,7 +103,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSButton" id="244571541">
|
<object class="NSButton" id="244571541">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">292</int>
|
||||||
<string key="NSFrame">{{41, 17}, {25, 23}}</string>
|
<string key="NSFrame">{{41, 17}, {25, 23}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -128,7 +128,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSScrollView" id="776974664">
|
<object class="NSScrollView" id="776974664">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">274</int>
|
||||||
<object class="NSMutableArray" key="NSSubviews">
|
<object class="NSMutableArray" key="NSSubviews">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSClipView" id="8658574">
|
<object class="NSClipView" id="8658574">
|
||||||
@ -139,7 +139,7 @@
|
|||||||
<object class="NSTableView" id="849333466">
|
<object class="NSTableView" id="849333466">
|
||||||
<reference key="NSNextResponder" ref="8658574"/>
|
<reference key="NSNextResponder" ref="8658574"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">256</int>
|
||||||
<string key="NSFrameSize">{224, 282}</string>
|
<string key="NSFrameSize">{224, 372}</string>
|
||||||
<reference key="NSSuperview" ref="8658574"/>
|
<reference key="NSSuperview" ref="8658574"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -275,7 +275,7 @@
|
|||||||
<int key="NSTableViewDraggingDestinationStyle">0</int>
|
<int key="NSTableViewDraggingDestinationStyle">0</int>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{1, 1}, {223, 282}}</string>
|
<string key="NSFrame">{{1, 1}, {223, 372}}</string>
|
||||||
<reference key="NSSuperview" ref="776974664"/>
|
<reference key="NSSuperview" ref="776974664"/>
|
||||||
<reference key="NSNextKeyView" ref="849333466"/>
|
<reference key="NSNextKeyView" ref="849333466"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -306,7 +306,7 @@
|
|||||||
<double key="NSPercent">0.91812865497076024</double>
|
<double key="NSPercent">0.91812865497076024</double>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{17, 40}, {225, 284}}</string>
|
<string key="NSFrame">{{17, 40}, {225, 374}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<reference key="NSNextKeyView" ref="8658574"/>
|
<reference key="NSNextKeyView" ref="8658574"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -318,8 +318,8 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSButton" id="538356055">
|
<object class="NSButton" id="538356055">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">265</int>
|
||||||
<string key="NSFrame">{{296, 254}, {273, 18}}</string>
|
<string key="NSFrame">{{291, 356}, {273, 18}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -341,8 +341,8 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSTextField" id="889877302">
|
<object class="NSTextField" id="889877302">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">265</int>
|
||||||
<string key="NSFrame">{{341, 292}, {249, 22}}</string>
|
<string key="NSFrame">{{341, 392}, {249, 22}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -369,8 +369,8 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSPopUpButton" id="801412726">
|
<object class="NSPopUpButton" id="801412726">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">265</int>
|
||||||
<string key="NSFrame">{{273, 185}, {320, 26}}</string>
|
<string key="NSFrame">{{273, 193}, {320, 26}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -440,10 +440,77 @@
|
|||||||
<int key="NSArrowPosition">2</int>
|
<int key="NSArrowPosition">2</int>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="NSPopUpButton" id="451647466">
|
||||||
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
|
<int key="NSvFlags">265</int>
|
||||||
|
<string key="NSFrame">{{273, 257}, {320, 26}}</string>
|
||||||
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
|
<bool key="NSEnabled">YES</bool>
|
||||||
|
<object class="NSPopUpButtonCell" key="NSCell" id="970826243">
|
||||||
|
<int key="NSCellFlags">-2076049856</int>
|
||||||
|
<int key="NSCellFlags2">2048</int>
|
||||||
|
<reference key="NSSupport" ref="696441443"/>
|
||||||
|
<reference key="NSControlView" ref="451647466"/>
|
||||||
|
<int key="NSButtonFlags">112869631</int>
|
||||||
|
<int key="NSButtonFlags2">129</int>
|
||||||
|
<string key="NSAlternateContents"/>
|
||||||
|
<string key="NSKeyEquivalent"/>
|
||||||
|
<int key="NSPeriodicDelay">400</int>
|
||||||
|
<int key="NSPeriodicInterval">75</int>
|
||||||
|
<object class="NSMenuItem" key="NSMenuItem" id="903120255">
|
||||||
|
<reference key="NSMenu" ref="790880658"/>
|
||||||
|
<string key="NSTitle">Choose one</string>
|
||||||
|
<string key="NSKeyEquiv"/>
|
||||||
|
<int key="NSKeyEquivModMask">1048576</int>
|
||||||
|
<int key="NSMnemonicLoc">2147483647</int>
|
||||||
|
<int key="NSState">1</int>
|
||||||
|
<reference key="NSOnImage" ref="615977438"/>
|
||||||
|
<reference key="NSMixedImage" ref="445532764"/>
|
||||||
|
<string key="NSAction">_popUpItemAction:</string>
|
||||||
|
<reference key="NSTarget" ref="970826243"/>
|
||||||
|
</object>
|
||||||
|
<bool key="NSMenuItemRespectAlignment">YES</bool>
|
||||||
|
<object class="NSMenu" key="NSMenu" id="790880658">
|
||||||
|
<string key="NSTitle">OtherViews</string>
|
||||||
|
<object class="NSMutableArray" key="NSMenuItems">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<reference ref="903120255"/>
|
||||||
|
<object class="NSMenuItem" id="778262848">
|
||||||
|
<reference key="NSMenu" ref="790880658"/>
|
||||||
|
<string key="NSTitle">Item 2</string>
|
||||||
|
<string key="NSKeyEquiv"/>
|
||||||
|
<int key="NSKeyEquivModMask">1048576</int>
|
||||||
|
<int key="NSMnemonicLoc">2147483647</int>
|
||||||
|
<reference key="NSOnImage" ref="615977438"/>
|
||||||
|
<reference key="NSMixedImage" ref="445532764"/>
|
||||||
|
<string key="NSAction">_popUpItemAction:</string>
|
||||||
|
<reference key="NSTarget" ref="970826243"/>
|
||||||
|
</object>
|
||||||
|
<object class="NSMenuItem" id="195135854">
|
||||||
|
<reference key="NSMenu" ref="790880658"/>
|
||||||
|
<string key="NSTitle">Item 3</string>
|
||||||
|
<string key="NSKeyEquiv"/>
|
||||||
|
<int key="NSKeyEquivModMask">1048576</int>
|
||||||
|
<int key="NSMnemonicLoc">2147483647</int>
|
||||||
|
<reference key="NSOnImage" ref="615977438"/>
|
||||||
|
<reference key="NSMixedImage" ref="445532764"/>
|
||||||
|
<string key="NSAction">_popUpItemAction:</string>
|
||||||
|
<reference key="NSTarget" ref="970826243"/>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<reference key="NSMenuFont" ref="696441443"/>
|
||||||
|
</object>
|
||||||
|
<int key="NSPreferredEdge">1</int>
|
||||||
|
<bool key="NSUsesItemFromMenu">YES</bool>
|
||||||
|
<bool key="NSAltersState">YES</bool>
|
||||||
|
<int key="NSArrowPosition">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSTextField" id="753545988">
|
<object class="NSTextField" id="753545988">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">265</int>
|
||||||
<string key="NSFrame">{{261, 294}, {75, 17}}</string>
|
<string key="NSFrame">{{261, 394}, {75, 17}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -459,8 +526,8 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSTextField" id="840157770">
|
<object class="NSTextField" id="840157770">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">265</int>
|
||||||
<string key="NSFrame">{{261, 217}, {105, 17}}</string>
|
<string key="NSFrame">{{261, 226}, {105, 17}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -474,9 +541,26 @@
|
|||||||
<reference key="NSTextColor" ref="399750419"/>
|
<reference key="NSTextColor" ref="399750419"/>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="NSTextField" id="459566505">
|
||||||
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
|
<int key="NSvFlags">265</int>
|
||||||
|
<string key="NSFrame">{{261, 290}, {105, 17}}</string>
|
||||||
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
|
<bool key="NSEnabled">YES</bool>
|
||||||
|
<object class="NSTextFieldCell" key="NSCell" id="534245320">
|
||||||
|
<int key="NSCellFlags">68288064</int>
|
||||||
|
<int key="NSCellFlags2">272630784</int>
|
||||||
|
<string key="NSContents">Optimize for:</string>
|
||||||
|
<reference key="NSSupport" ref="696441443"/>
|
||||||
|
<reference key="NSControlView" ref="459566505"/>
|
||||||
|
<reference key="NSBackgroundColor" ref="965844506"/>
|
||||||
|
<reference key="NSTextColor" ref="399750419"/>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSButton" id="962924480">
|
<object class="NSButton" id="962924480">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">289</int>
|
||||||
<string key="NSFrame">{{276, 40}, {25, 23}}</string>
|
<string key="NSFrame">{{276, 40}, {25, 23}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -498,7 +582,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSButton" id="705215911">
|
<object class="NSButton" id="705215911">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">289</int>
|
||||||
<string key="NSFrame">{{300, 40}, {25, 23}}</string>
|
<string key="NSFrame">{{300, 40}, {25, 23}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -520,7 +604,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSScrollView" id="610703353">
|
<object class="NSScrollView" id="610703353">
|
||||||
<reference key="NSNextResponder" ref="60314308"/>
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">273</int>
|
||||||
<object class="NSMutableArray" key="NSSubviews">
|
<object class="NSMutableArray" key="NSSubviews">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSClipView" id="844110079">
|
<object class="NSClipView" id="844110079">
|
||||||
@ -531,7 +615,7 @@
|
|||||||
<object class="NSTableView" id="714838401">
|
<object class="NSTableView" id="714838401">
|
||||||
<reference key="NSNextResponder" ref="844110079"/>
|
<reference key="NSNextResponder" ref="844110079"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">256</int>
|
||||||
<string key="NSFrameSize">{312, 95}</string>
|
<string key="NSFrameSize">{312, 102}</string>
|
||||||
<reference key="NSSuperview" ref="844110079"/>
|
<reference key="NSSuperview" ref="844110079"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -623,7 +707,7 @@
|
|||||||
<int key="NSTableViewDraggingDestinationStyle">0</int>
|
<int key="NSTableViewDraggingDestinationStyle">0</int>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{1, 17}, {312, 95}}</string>
|
<string key="NSFrame">{{1, 17}, {312, 102}}</string>
|
||||||
<reference key="NSSuperview" ref="610703353"/>
|
<reference key="NSSuperview" ref="610703353"/>
|
||||||
<reference key="NSNextKeyView" ref="714838401"/>
|
<reference key="NSNextKeyView" ref="714838401"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -639,7 +723,7 @@
|
|||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<reference key="NSTarget" ref="610703353"/>
|
<reference key="NSTarget" ref="610703353"/>
|
||||||
<string key="NSAction">_doScroller:</string>
|
<string key="NSAction">_doScroller:</string>
|
||||||
<double key="NSPercent">0.8529411764705882</double>
|
<double key="NSPercent">0.96938775510204078</double>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSScroller" id="522064761">
|
<object class="NSScroller" id="522064761">
|
||||||
<reference key="NSNextResponder" ref="610703353"/>
|
<reference key="NSNextResponder" ref="610703353"/>
|
||||||
@ -669,7 +753,7 @@
|
|||||||
</object>
|
</object>
|
||||||
<reference ref="188199142"/>
|
<reference ref="188199142"/>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{276, 63}, {314, 113}}</string>
|
<string key="NSFrame">{{276, 63}, {314, 120}}</string>
|
||||||
<reference key="NSSuperview" ref="60314308"/>
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
<reference key="NSNextKeyView" ref="844110079"/>
|
<reference key="NSNextKeyView" ref="844110079"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -681,8 +765,32 @@
|
|||||||
<reference key="NSCornerView" ref="188199142"/>
|
<reference key="NSCornerView" ref="188199142"/>
|
||||||
<bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
|
<bytes key="NSScrollAmts">QSAAAEEgAABBmAAAQZgAAA</bytes>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="NSButton" id="160987209">
|
||||||
|
<reference key="NSNextResponder" ref="60314308"/>
|
||||||
|
<int key="NSvFlags">265</int>
|
||||||
|
<string key="NSFrame">{{291, 323}, {285, 18}}</string>
|
||||||
|
<reference key="NSSuperview" ref="60314308"/>
|
||||||
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
|
<bool key="NSEnabled">YES</bool>
|
||||||
|
<object class="NSButtonCell" key="NSCell" id="565787077">
|
||||||
|
<int key="NSCellFlags">-2080244224</int>
|
||||||
|
<int key="NSCellFlags2">0</int>
|
||||||
|
<string key="NSContents">Send DNS requests through this server</string>
|
||||||
|
<reference key="NSSupport" ref="696441443"/>
|
||||||
|
<reference key="NSControlView" ref="160987209"/>
|
||||||
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
|
<int key="NSButtonFlags2">2</int>
|
||||||
|
<reference key="NSNormalImage" ref="581816235"/>
|
||||||
|
<reference key="NSAlternateImage" ref="753862261"/>
|
||||||
|
<string key="NSAlternateContents"/>
|
||||||
|
<string key="NSKeyEquivalent"/>
|
||||||
|
<int key="NSPeriodicDelay">200</int>
|
||||||
|
<int key="NSPeriodicInterval">25</int>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{10, 33}, {607, 327}}</string>
|
</object>
|
||||||
|
</object>
|
||||||
|
<string key="NSFrame">{{10, 33}, {607, 427}}</string>
|
||||||
|
<reference key="NSSuperview" ref="389252804"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSLabel">SSH Servers</string>
|
<string key="NSLabel">SSH Servers</string>
|
||||||
@ -692,14 +800,14 @@
|
|||||||
<object class="NSTabViewItem" id="740075218">
|
<object class="NSTabViewItem" id="740075218">
|
||||||
<string key="NSIdentifier">2</string>
|
<string key="NSIdentifier">2</string>
|
||||||
<object class="NSView" key="NSView" id="187214803">
|
<object class="NSView" key="NSView" id="187214803">
|
||||||
<reference key="NSNextResponder" ref="389252804"/>
|
<nil key="NSNextResponder"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">274</int>
|
||||||
<object class="NSMutableArray" key="NSSubviews">
|
<object class="NSMutableArray" key="NSSubviews">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSButton" id="625816566">
|
<object class="NSButton" id="625816566">
|
||||||
<reference key="NSNextResponder" ref="187214803"/>
|
<reference key="NSNextResponder" ref="187214803"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">269</int>
|
||||||
<string key="NSFrame">{{189, 287}, {177, 29}}</string>
|
<string key="NSFrame">{{195, 374}, {236, 29}}</string>
|
||||||
<reference key="NSSuperview" ref="187214803"/>
|
<reference key="NSSuperview" ref="187214803"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -721,8 +829,8 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSButton" id="633518934">
|
<object class="NSButton" id="633518934">
|
||||||
<reference key="NSNextResponder" ref="187214803"/>
|
<reference key="NSNextResponder" ref="187214803"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">269</int>
|
||||||
<string key="NSFrame">{{189, 256}, {270, 29}}</string>
|
<string key="NSFrame">{{195, 343}, {236, 29}}</string>
|
||||||
<reference key="NSSuperview" ref="187214803"/>
|
<reference key="NSSuperview" ref="187214803"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
@ -744,15 +852,15 @@
|
|||||||
</object>
|
</object>
|
||||||
<object class="NSButton" id="625121428">
|
<object class="NSButton" id="625121428">
|
||||||
<reference key="NSNextResponder" ref="187214803"/>
|
<reference key="NSNextResponder" ref="187214803"/>
|
||||||
<int key="NSvFlags">268</int>
|
<int key="NSvFlags">269</int>
|
||||||
<string key="NSFrame">{{189, 225}, {270, 29}}</string>
|
<string key="NSFrame">{{195, 312}, {236, 29}}</string>
|
||||||
<reference key="NSSuperview" ref="187214803"/>
|
<reference key="NSSuperview" ref="187214803"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<bool key="NSEnabled">YES</bool>
|
<bool key="NSEnabled">YES</bool>
|
||||||
<object class="NSButtonCell" key="NSCell" id="132399775">
|
<object class="NSButtonCell" key="NSCell" id="132399775">
|
||||||
<int key="NSCellFlags">67239424</int>
|
<int key="NSCellFlags">67239424</int>
|
||||||
<int key="NSCellFlags2">0</int>
|
<int key="NSCellFlags2">0</int>
|
||||||
<string key="NSContents">Send debug information to log</string>
|
<string key="NSContents">Enable debug messages</string>
|
||||||
<reference key="NSSupport" ref="696441443"/>
|
<reference key="NSSupport" ref="696441443"/>
|
||||||
<reference key="NSControlView" ref="625121428"/>
|
<reference key="NSControlView" ref="625121428"/>
|
||||||
<int key="NSButtonFlags">1211912703</int>
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
@ -766,8 +874,7 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{10, 33}, {607, 327}}</string>
|
<string key="NSFrame">{{10, 33}, {607, 427}}</string>
|
||||||
<reference key="NSSuperview" ref="389252804"/>
|
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSLabel">Options</string>
|
<string key="NSLabel">Options</string>
|
||||||
@ -783,7 +890,7 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSScrollView" id="486362220">
|
<object class="NSScrollView" id="486362220">
|
||||||
<reference key="NSNextResponder" ref="311013698"/>
|
<reference key="NSNextResponder" ref="311013698"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">274</int>
|
||||||
<object class="NSMutableArray" key="NSSubviews">
|
<object class="NSMutableArray" key="NSSubviews">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSClipView" id="708990027">
|
<object class="NSClipView" id="708990027">
|
||||||
@ -794,7 +901,7 @@
|
|||||||
<object class="NSTextView" id="758761310">
|
<object class="NSTextView" id="758761310">
|
||||||
<reference key="NSNextResponder" ref="708990027"/>
|
<reference key="NSNextResponder" ref="708990027"/>
|
||||||
<int key="NSvFlags">2322</int>
|
<int key="NSvFlags">2322</int>
|
||||||
<string key="NSFrameSize">{596, 14}</string>
|
<string key="NSFrameSize">{596, 114}</string>
|
||||||
<reference key="NSSuperview" ref="708990027"/>
|
<reference key="NSSuperview" ref="708990027"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<object class="NSTextContainer" key="NSTextContainer" id="548968659">
|
<object class="NSTextContainer" key="NSTextContainer" id="548968659">
|
||||||
@ -874,7 +981,7 @@
|
|||||||
<nil key="NSDelegate"/>
|
<nil key="NSDelegate"/>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{1, 1}, {596, 310}}</string>
|
<string key="NSFrame">{{1, 1}, {596, 410}}</string>
|
||||||
<reference key="NSSuperview" ref="486362220"/>
|
<reference key="NSSuperview" ref="486362220"/>
|
||||||
<reference key="NSNextKeyView" ref="758761310"/>
|
<reference key="NSNextKeyView" ref="758761310"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -889,7 +996,7 @@
|
|||||||
<object class="NSScroller" id="794963499">
|
<object class="NSScroller" id="794963499">
|
||||||
<reference key="NSNextResponder" ref="486362220"/>
|
<reference key="NSNextResponder" ref="486362220"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">256</int>
|
||||||
<string key="NSFrame">{{597, 1}, {15, 310}}</string>
|
<string key="NSFrame">{{597, 1}, {15, 410}}</string>
|
||||||
<reference key="NSSuperview" ref="486362220"/>
|
<reference key="NSSuperview" ref="486362220"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<reference key="NSTarget" ref="486362220"/>
|
<reference key="NSTarget" ref="486362220"/>
|
||||||
@ -900,7 +1007,7 @@
|
|||||||
<object class="NSScroller" id="324242772">
|
<object class="NSScroller" id="324242772">
|
||||||
<reference key="NSNextResponder" ref="486362220"/>
|
<reference key="NSNextResponder" ref="486362220"/>
|
||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">256</int>
|
||||||
<string key="NSFrame">{{1, 311}, {596, 15}}</string>
|
<string key="NSFrame">{{1, 411}, {596, 15}}</string>
|
||||||
<reference key="NSSuperview" ref="486362220"/>
|
<reference key="NSSuperview" ref="486362220"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
<int key="NSsFlags">1</int>
|
<int key="NSsFlags">1</int>
|
||||||
@ -910,7 +1017,7 @@
|
|||||||
<double key="NSPercent">0.94565218687057495</double>
|
<double key="NSPercent">0.94565218687057495</double>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{-3, -3}, {613, 327}}</string>
|
<string key="NSFrame">{{-3, -3}, {613, 427}}</string>
|
||||||
<reference key="NSSuperview" ref="311013698"/>
|
<reference key="NSSuperview" ref="311013698"/>
|
||||||
<reference key="NSNextKeyView" ref="708990027"/>
|
<reference key="NSNextKeyView" ref="708990027"/>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
@ -920,7 +1027,7 @@
|
|||||||
<reference key="NSContentView" ref="708990027"/>
|
<reference key="NSContentView" ref="708990027"/>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrame">{{10, 33}, {607, 327}}</string>
|
<string key="NSFrame">{{10, 33}, {607, 427}}</string>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSLabel">Log Messages</string>
|
<string key="NSLabel">Log Messages</string>
|
||||||
@ -928,17 +1035,17 @@
|
|||||||
<reference key="NSTabView" ref="389252804"/>
|
<reference key="NSTabView" ref="389252804"/>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<reference key="NSSelectedTabViewItem" ref="740075218"/>
|
<reference key="NSSelectedTabViewItem" ref="762265164"/>
|
||||||
<reference key="NSFont" ref="696441443"/>
|
<reference key="NSFont" ref="696441443"/>
|
||||||
<int key="NSTvFlags">0</int>
|
<int key="NSTvFlags">0</int>
|
||||||
<bool key="NSDrawsBackground">YES</bool>
|
<bool key="NSDrawsBackground">YES</bool>
|
||||||
<object class="NSMutableArray" key="NSSubviews">
|
<object class="NSMutableArray" key="NSSubviews">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<reference ref="187214803"/>
|
<reference ref="60314308"/>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSFrameSize">{611, 369}</string>
|
<string key="NSFrameSize">{611, 469}</string>
|
||||||
<reference key="NSSuperview"/>
|
<reference key="NSSuperview"/>
|
||||||
<object class="NSDictionary" key="NSViewAnimations">
|
<object class="NSDictionary" key="NSViewAnimations">
|
||||||
<string key="NS.key.0">subviews</string>
|
<string key="NS.key.0">subviews</string>
|
||||||
@ -962,8 +1069,8 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
<int key="NSViewLayerContentsRedrawPolicy">2</int>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSScreenRect">{{0, 0}, {800, 578}}</string>
|
<string key="NSScreenRect">{{0, 0}, {1280, 778}}</string>
|
||||||
<string key="NSMinSize">{213, 129}</string>
|
<string key="NSMinSize">{611, 491}</string>
|
||||||
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSArrayController" id="678105904">
|
<object class="NSArrayController" id="678105904">
|
||||||
@ -979,10 +1086,6 @@
|
|||||||
<string key="NSClassName">SshuttleController</string>
|
<string key="NSClassName">SshuttleController</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSUserDefaultsController" id="582889489">
|
<object class="NSUserDefaultsController" id="582889489">
|
||||||
<object class="NSMutableArray" key="NSDeclaredKeys">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>debug</string>
|
|
||||||
</object>
|
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
<bool key="NSSharedInstance">YES</bool>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSCustomObject" id="735871403">
|
<object class="NSCustomObject" id="735871403">
|
||||||
@ -1000,6 +1103,9 @@
|
|||||||
<string>statusMsg</string>
|
<string>statusMsg</string>
|
||||||
<string>status</string>
|
<string>status</string>
|
||||||
<string>isValid</string>
|
<string>isValid</string>
|
||||||
|
<string>useDns</string>
|
||||||
|
<string>title</string>
|
||||||
|
<string>latencyControl</string>
|
||||||
</object>
|
</object>
|
||||||
<string key="NSObjectClassName">SshuttleServer</string>
|
<string key="NSObjectClassName">SshuttleServer</string>
|
||||||
<bool key="NSEditable">YES</bool>
|
<bool key="NSEditable">YES</bool>
|
||||||
@ -1109,35 +1215,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">480</int>
|
<int key="connectionID">480</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBBindingConnection" key="connection">
|
|
||||||
<string key="label">value: arrangedObjects.host</string>
|
|
||||||
<reference key="source" ref="807059746"/>
|
|
||||||
<reference key="destination" ref="59237012"/>
|
|
||||||
<object class="NSNibBindingConnector" key="connector">
|
|
||||||
<reference key="NSSource" ref="807059746"/>
|
|
||||||
<reference key="NSDestination" ref="59237012"/>
|
|
||||||
<string key="NSLabel">value: arrangedObjects.host</string>
|
|
||||||
<string key="NSBinding">value</string>
|
|
||||||
<string key="NSKeyPath">arrangedObjects.host</string>
|
|
||||||
<object class="NSDictionary" key="NSOptions">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<object class="NSArray" key="dict.sortedKeys">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<string>NSConditionallySetsEditable</string>
|
|
||||||
<string>NSNullPlaceholder</string>
|
|
||||||
</object>
|
|
||||||
<object class="NSMutableArray" key="dict.values">
|
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
|
||||||
<boolean value="YES"/>
|
|
||||||
<string>Untitled</string>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="NSNibBindingConnectorVersion">2</int>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">495</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBBindingConnection" key="connection">
|
<object class="IBBindingConnection" key="connection">
|
||||||
<string key="label">selectedIndex: selection.autoNets</string>
|
<string key="label">selectedIndex: selection.autoNets</string>
|
||||||
@ -1454,6 +1531,83 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">557</int>
|
<int key="connectionID">557</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: selection.useDns</string>
|
||||||
|
<reference key="source" ref="160987209"/>
|
||||||
|
<reference key="destination" ref="59237012"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="160987209"/>
|
||||||
|
<reference key="NSDestination" ref="59237012"/>
|
||||||
|
<string key="NSLabel">value: selection.useDns</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">selection.useDns</string>
|
||||||
|
<object class="NSDictionary" key="NSOptions">
|
||||||
|
<string key="NS.key.0">NSNoSelectionPlaceholder</string>
|
||||||
|
<integer value="0" key="NS.object.0"/>
|
||||||
|
</object>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">572</int>
|
||||||
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: arrangedObjects.title</string>
|
||||||
|
<reference key="source" ref="807059746"/>
|
||||||
|
<reference key="destination" ref="59237012"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="807059746"/>
|
||||||
|
<reference key="NSDestination" ref="59237012"/>
|
||||||
|
<string key="NSLabel">value: arrangedObjects.title</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">arrangedObjects.title</string>
|
||||||
|
<object class="NSDictionary" key="NSOptions">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<object class="NSArray" key="dict.sortedKeys">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<string>NSConditionallySetsEditable</string>
|
||||||
|
<string>NSNullPlaceholder</string>
|
||||||
|
</object>
|
||||||
|
<object class="NSMutableArray" key="dict.values">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<boolean value="YES"/>
|
||||||
|
<string>Untitled</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">573</int>
|
||||||
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">selectedIndex: selection.latencyControl</string>
|
||||||
|
<reference key="source" ref="451647466"/>
|
||||||
|
<reference key="destination" ref="59237012"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="451647466"/>
|
||||||
|
<reference key="NSDestination" ref="59237012"/>
|
||||||
|
<string key="NSLabel">selectedIndex: selection.latencyControl</string>
|
||||||
|
<string key="NSBinding">selectedIndex</string>
|
||||||
|
<string key="NSKeyPath">selection.latencyControl</string>
|
||||||
|
<object class="NSDictionary" key="NSOptions">
|
||||||
|
<string key="NS.key.0">NSNoSelectionPlaceholder</string>
|
||||||
|
<real value="1" key="NS.object.0"/>
|
||||||
|
</object>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">581</int>
|
||||||
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBOutletConnection" key="connection">
|
||||||
|
<string key="label">latencyControlField</string>
|
||||||
|
<reference key="source" ref="307402018"/>
|
||||||
|
<reference key="destination" ref="451647466"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">582</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@ -1554,15 +1708,18 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<reference ref="889877302"/>
|
<reference ref="889877302"/>
|
||||||
<reference ref="753545988"/>
|
<reference ref="753545988"/>
|
||||||
|
<reference ref="26015719"/>
|
||||||
|
<reference ref="244571541"/>
|
||||||
|
<reference ref="776974664"/>
|
||||||
|
<reference ref="962924480"/>
|
||||||
|
<reference ref="705215911"/>
|
||||||
|
<reference ref="610703353"/>
|
||||||
|
<reference ref="160987209"/>
|
||||||
<reference ref="801412726"/>
|
<reference ref="801412726"/>
|
||||||
<reference ref="840157770"/>
|
<reference ref="840157770"/>
|
||||||
<reference ref="538356055"/>
|
<reference ref="538356055"/>
|
||||||
<reference ref="776974664"/>
|
<reference ref="451647466"/>
|
||||||
<reference ref="610703353"/>
|
<reference ref="459566505"/>
|
||||||
<reference ref="26015719"/>
|
|
||||||
<reference ref="244571541"/>
|
|
||||||
<reference ref="962924480"/>
|
|
||||||
<reference ref="705215911"/>
|
|
||||||
</object>
|
</object>
|
||||||
<reference key="parent" ref="762265164"/>
|
<reference key="parent" ref="762265164"/>
|
||||||
</object>
|
</object>
|
||||||
@ -1962,6 +2119,78 @@
|
|||||||
<reference key="object" ref="132399775"/>
|
<reference key="object" ref="132399775"/>
|
||||||
<reference key="parent" ref="625121428"/>
|
<reference key="parent" ref="625121428"/>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">561</int>
|
||||||
|
<reference key="object" ref="160987209"/>
|
||||||
|
<object class="NSMutableArray" key="children">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<reference ref="565787077"/>
|
||||||
|
</object>
|
||||||
|
<reference key="parent" ref="60314308"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">562</int>
|
||||||
|
<reference key="object" ref="565787077"/>
|
||||||
|
<reference key="parent" ref="160987209"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">574</int>
|
||||||
|
<reference key="object" ref="451647466"/>
|
||||||
|
<object class="NSMutableArray" key="children">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<reference ref="970826243"/>
|
||||||
|
</object>
|
||||||
|
<reference key="parent" ref="60314308"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">575</int>
|
||||||
|
<reference key="object" ref="970826243"/>
|
||||||
|
<object class="NSMutableArray" key="children">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<reference ref="790880658"/>
|
||||||
|
</object>
|
||||||
|
<reference key="parent" ref="451647466"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">576</int>
|
||||||
|
<reference key="object" ref="790880658"/>
|
||||||
|
<object class="NSMutableArray" key="children">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<reference ref="195135854"/>
|
||||||
|
<reference ref="778262848"/>
|
||||||
|
<reference ref="903120255"/>
|
||||||
|
</object>
|
||||||
|
<reference key="parent" ref="970826243"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">577</int>
|
||||||
|
<reference key="object" ref="195135854"/>
|
||||||
|
<reference key="parent" ref="790880658"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">578</int>
|
||||||
|
<reference key="object" ref="778262848"/>
|
||||||
|
<reference key="parent" ref="790880658"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">579</int>
|
||||||
|
<reference key="object" ref="903120255"/>
|
||||||
|
<reference key="parent" ref="790880658"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">583</int>
|
||||||
|
<reference key="object" ref="459566505"/>
|
||||||
|
<object class="NSMutableArray" key="children">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<reference ref="534245320"/>
|
||||||
|
</object>
|
||||||
|
<reference key="parent" ref="60314308"/>
|
||||||
|
</object>
|
||||||
|
<object class="IBObjectRecord">
|
||||||
|
<int key="objectID">584</int>
|
||||||
|
<reference key="object" ref="534245320"/>
|
||||||
|
<reference key="parent" ref="459566505"/>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||||
@ -2055,6 +2284,18 @@
|
|||||||
<string>552.IBAttributePlaceholdersKey</string>
|
<string>552.IBAttributePlaceholdersKey</string>
|
||||||
<string>552.IBPluginDependency</string>
|
<string>552.IBPluginDependency</string>
|
||||||
<string>553.IBPluginDependency</string>
|
<string>553.IBPluginDependency</string>
|
||||||
|
<string>561.IBAttributePlaceholdersKey</string>
|
||||||
|
<string>561.IBPluginDependency</string>
|
||||||
|
<string>562.IBPluginDependency</string>
|
||||||
|
<string>574.IBAttributePlaceholdersKey</string>
|
||||||
|
<string>574.IBPluginDependency</string>
|
||||||
|
<string>575.IBPluginDependency</string>
|
||||||
|
<string>576.IBPluginDependency</string>
|
||||||
|
<string>577.IBPluginDependency</string>
|
||||||
|
<string>578.IBPluginDependency</string>
|
||||||
|
<string>579.IBPluginDependency</string>
|
||||||
|
<string>583.IBPluginDependency</string>
|
||||||
|
<string>584.IBPluginDependency</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableArray" key="dict.values">
|
<object class="NSMutableArray" key="dict.values">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
@ -2062,13 +2303,13 @@
|
|||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>{{317, 387}, {611, 369}}</string>
|
<string>{{324, 171}, {611, 469}}</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string>{{317, 387}, {611, 369}}</string>
|
<string>{{324, 171}, {611, 469}}</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<boolean value="NO"/>
|
<boolean value="NO"/>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>{213, 107}</string>
|
<string>{611, 469}</string>
|
||||||
<object class="NSMutableDictionary">
|
<object class="NSMutableDictionary">
|
||||||
<string key="NS.key.0">ToolTip</string>
|
<string key="NS.key.0">ToolTip</string>
|
||||||
<object class="IBToolTipAttribute" key="NS.object.0">
|
<object class="IBToolTipAttribute" key="NS.object.0">
|
||||||
@ -2232,6 +2473,32 @@
|
|||||||
</object>
|
</object>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<object class="NSMutableDictionary">
|
||||||
|
<string key="NS.key.0">ToolTip</string>
|
||||||
|
<object class="IBToolTipAttribute" key="NS.object.0">
|
||||||
|
<string key="name">ToolTip</string>
|
||||||
|
<reference key="object" ref="160987209"/>
|
||||||
|
<string key="toolTip">Search for server names on the remote end and add them to your computer's /etc/hosts file.</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<object class="NSMutableDictionary">
|
||||||
|
<string key="NS.key.0">ToolTip</string>
|
||||||
|
<object class="IBToolTipAttribute" key="NS.object.0">
|
||||||
|
<string key="name">ToolTip</string>
|
||||||
|
<reference key="object" ref="451647466"/>
|
||||||
|
<string key="toolTip">Choose which network traffic should be routed over the VPN.</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||||
@ -2250,7 +2517,7 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">557</int>
|
<int key="maxID">584</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
@ -2280,6 +2547,7 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<string>autoReconnectField</string>
|
<string>autoReconnectField</string>
|
||||||
<string>debugField</string>
|
<string>debugField</string>
|
||||||
|
<string>latencyControlField</string>
|
||||||
<string>logField</string>
|
<string>logField</string>
|
||||||
<string>prefsWindow</string>
|
<string>prefsWindow</string>
|
||||||
<string>routingField</string>
|
<string>routingField</string>
|
||||||
@ -2295,6 +2563,7 @@
|
|||||||
<string>id</string>
|
<string>id</string>
|
||||||
<string>id</string>
|
<string>id</string>
|
||||||
<string>id</string>
|
<string>id</string>
|
||||||
|
<string>id</string>
|
||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
@ -2,7 +2,8 @@ import sys, os, pty
|
|||||||
from AppKit import *
|
from AppKit import *
|
||||||
import my, models, askpass
|
import my, models, askpass
|
||||||
|
|
||||||
def sshuttle_args(host, auto_nets, auto_hosts, nets, debug):
|
def sshuttle_args(host, auto_nets, auto_hosts, dns, nets, debug,
|
||||||
|
no_latency_control):
|
||||||
argv = [my.bundle_path('sshuttle/sshuttle', ''), '-r', host]
|
argv = [my.bundle_path('sshuttle/sshuttle', ''), '-r', host]
|
||||||
assert(argv[0])
|
assert(argv[0])
|
||||||
if debug:
|
if debug:
|
||||||
@ -11,6 +12,10 @@ def sshuttle_args(host, auto_nets, auto_hosts, nets, debug):
|
|||||||
argv.append('--auto-nets')
|
argv.append('--auto-nets')
|
||||||
if auto_hosts:
|
if auto_hosts:
|
||||||
argv.append('--auto-hosts')
|
argv.append('--auto-hosts')
|
||||||
|
if dns:
|
||||||
|
argv.append('--dns')
|
||||||
|
if no_latency_control:
|
||||||
|
argv.append('--no-latency-control')
|
||||||
argv += nets
|
argv += nets
|
||||||
return argv
|
return argv
|
||||||
|
|
||||||
@ -131,6 +136,7 @@ class SshuttleController(NSObject):
|
|||||||
prefsWindow = objc.IBOutlet()
|
prefsWindow = objc.IBOutlet()
|
||||||
serversController = objc.IBOutlet()
|
serversController = objc.IBOutlet()
|
||||||
logField = objc.IBOutlet()
|
logField = objc.IBOutlet()
|
||||||
|
latencyControlField = objc.IBOutlet()
|
||||||
|
|
||||||
servers = []
|
servers = []
|
||||||
conns = {}
|
conns = {}
|
||||||
@ -156,11 +162,14 @@ class SshuttleController(NSObject):
|
|||||||
manual_nets = ['0/0']
|
manual_nets = ['0/0']
|
||||||
else:
|
else:
|
||||||
manual_nets = []
|
manual_nets = []
|
||||||
|
noLatencyControl = (server.latencyControl() != models.LAT_INTERACTIVE)
|
||||||
conn = Runner(sshuttle_args(host,
|
conn = Runner(sshuttle_args(host,
|
||||||
auto_nets = nets_mode == models.NET_AUTO,
|
auto_nets = nets_mode == models.NET_AUTO,
|
||||||
auto_hosts = server.autoHosts(),
|
auto_hosts = server.autoHosts(),
|
||||||
|
dns = server.useDns(),
|
||||||
nets = manual_nets,
|
nets = manual_nets,
|
||||||
debug = self.debugField.state()),
|
debug = self.debugField.state(),
|
||||||
|
no_latency_control = noLatencyControl),
|
||||||
logfunc=logfunc, promptfunc=promptfunc,
|
logfunc=logfunc, promptfunc=promptfunc,
|
||||||
serverobj=server)
|
serverobj=server)
|
||||||
self.conns[host] = conn
|
self.conns[host] = conn
|
||||||
@ -213,6 +222,7 @@ class SshuttleController(NSObject):
|
|||||||
if len(self.servers):
|
if len(self.servers):
|
||||||
for i in self.servers:
|
for i in self.servers:
|
||||||
host = i.host()
|
host = i.host()
|
||||||
|
title = i.title()
|
||||||
want = i.wantConnect()
|
want = i.wantConnect()
|
||||||
connected = i.connected()
|
connected = i.connected()
|
||||||
numnets = len(list(i.nets()))
|
numnets = len(list(i.nets()))
|
||||||
@ -222,9 +232,9 @@ class SshuttleController(NSObject):
|
|||||||
additem('Connect %s (no routes)' % host, None, i)
|
additem('Connect %s (no routes)' % host, None, i)
|
||||||
elif want:
|
elif want:
|
||||||
any_conn = i
|
any_conn = i
|
||||||
additem('Disconnect %s' % host, self.cmd_disconnect, i)
|
additem('Disconnect %s' % title, self.cmd_disconnect, i)
|
||||||
else:
|
else:
|
||||||
additem('Connect %s' % host, self.cmd_connect, i)
|
additem('Connect %s' % title, self.cmd_connect, i)
|
||||||
if not want:
|
if not want:
|
||||||
msg = 'Off'
|
msg = 'Off'
|
||||||
elif i.error():
|
elif i.error():
|
||||||
@ -236,12 +246,6 @@ class SshuttleController(NSObject):
|
|||||||
msg = 'Connecting...'
|
msg = 'Connecting...'
|
||||||
any_inprogress = i
|
any_inprogress = i
|
||||||
addnote(' State: %s' % msg)
|
addnote(' State: %s' % msg)
|
||||||
if i.autoNets() == 0:
|
|
||||||
addnote(' Routes: All')
|
|
||||||
elif i.autoNets() == 2:
|
|
||||||
addnote(' Routes: Auto')
|
|
||||||
else:
|
|
||||||
addnote(' Routes: Custom')
|
|
||||||
else:
|
else:
|
||||||
addnote('No servers defined yet')
|
addnote('No servers defined yet')
|
||||||
|
|
||||||
@ -279,13 +283,17 @@ class SshuttleController(NSObject):
|
|||||||
net.setWidth_(width)
|
net.setWidth_(width)
|
||||||
nl.append(net)
|
nl.append(net)
|
||||||
|
|
||||||
autoNets = s.get('autoNets', 1)
|
autoNets = s.get('autoNets', models.NET_AUTO)
|
||||||
autoHosts = s.get('autoHosts', 1)
|
autoHosts = s.get('autoHosts', True)
|
||||||
|
useDns = s.get('useDns', autoNets == models.NET_ALL)
|
||||||
|
latencyControl = s.get('latencyControl', models.LAT_INTERACTIVE)
|
||||||
srv = models.SshuttleServer.alloc().init()
|
srv = models.SshuttleServer.alloc().init()
|
||||||
srv.setHost_(host)
|
srv.setHost_(host)
|
||||||
srv.setAutoNets_(autoNets)
|
srv.setAutoNets_(autoNets)
|
||||||
srv.setAutoHosts_(autoHosts)
|
srv.setAutoHosts_(autoHosts)
|
||||||
srv.setNets_(nl)
|
srv.setNets_(nl)
|
||||||
|
srv.setUseDns_(useDns)
|
||||||
|
srv.setLatencyControl_(latencyControl)
|
||||||
sl.append(srv)
|
sl.append(srv)
|
||||||
self.serversController.addObjects_(sl)
|
self.serversController.addObjects_(sl)
|
||||||
self.serversController.setSelectionIndex_(0)
|
self.serversController.setSelectionIndex_(0)
|
||||||
@ -303,7 +311,9 @@ class SshuttleController(NSObject):
|
|||||||
d = dict(host=s.host(),
|
d = dict(host=s.host(),
|
||||||
nets=nets,
|
nets=nets,
|
||||||
autoNets=s.autoNets(),
|
autoNets=s.autoNets(),
|
||||||
autoHosts=s.autoHosts())
|
autoHosts=s.autoHosts(),
|
||||||
|
useDns=s.useDns(),
|
||||||
|
latencyControl=s.latencyControl())
|
||||||
l.append(d)
|
l.append(d)
|
||||||
my.Defaults().setObject_forKey_(l, 'servers')
|
my.Defaults().setObject_forKey_(l, 'servers')
|
||||||
self.fill_menu()
|
self.fill_menu()
|
||||||
@ -315,6 +325,11 @@ class SshuttleController(NSObject):
|
|||||||
tf('Determine automatically')
|
tf('Determine automatically')
|
||||||
tf('Custom...')
|
tf('Custom...')
|
||||||
|
|
||||||
|
self.latencyControlField.removeAllItems()
|
||||||
|
tf = self.latencyControlField.addItemWithTitle_
|
||||||
|
tf('Fast transfer')
|
||||||
|
tf('Low latency')
|
||||||
|
|
||||||
# Hmm, even when I mark this as !enabled in the .nib, it still comes
|
# Hmm, even when I mark this as !enabled in the .nib, it still comes
|
||||||
# through as enabled. So let's just disable it here (since we don't
|
# through as enabled. So let's just disable it here (since we don't
|
||||||
# support this feature yet).
|
# support this feature yet).
|
||||||
|
@ -58,6 +58,9 @@ NET_ALL = 0
|
|||||||
NET_AUTO = 1
|
NET_AUTO = 1
|
||||||
NET_MANUAL = 2
|
NET_MANUAL = 2
|
||||||
|
|
||||||
|
LAT_BANDWIDTH = 0
|
||||||
|
LAT_INTERACTIVE = 1
|
||||||
|
|
||||||
class SshuttleServer(NSObject):
|
class SshuttleServer(NSObject):
|
||||||
def init(self):
|
def init(self):
|
||||||
self = super(SshuttleServer, self).init()
|
self = super(SshuttleServer, self).init()
|
||||||
@ -93,10 +96,27 @@ class SshuttleServer(NSObject):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def title(self):
|
||||||
|
host = self.host()
|
||||||
|
if not host:
|
||||||
|
return host
|
||||||
|
an = self.autoNets()
|
||||||
|
suffix = ""
|
||||||
|
if an == NET_ALL:
|
||||||
|
suffix = " (all traffic)"
|
||||||
|
elif an == NET_MANUAL:
|
||||||
|
n = self.nets()
|
||||||
|
suffix = ' (%d subnet%s)' % (len(n), len(n)!=1 and 's' or '')
|
||||||
|
return self.host() + suffix
|
||||||
|
def setTitle_(self, v):
|
||||||
|
# title is always auto-generated
|
||||||
|
config_changed()
|
||||||
|
|
||||||
def host(self):
|
def host(self):
|
||||||
return getattr(self, '_k_host', None)
|
return getattr(self, '_k_host', None)
|
||||||
def setHost_(self, v):
|
def setHost_(self, v):
|
||||||
self._k_host = v
|
self._k_host = v
|
||||||
|
self.setTitle_(None)
|
||||||
config_changed()
|
config_changed()
|
||||||
@objc.accessor
|
@objc.accessor
|
||||||
def validateHost_error_(self, value, error):
|
def validateHost_error_(self, value, error):
|
||||||
@ -109,6 +129,7 @@ class SshuttleServer(NSObject):
|
|||||||
return getattr(self, '_k_nets', [])
|
return getattr(self, '_k_nets', [])
|
||||||
def setNets_(self, v):
|
def setNets_(self, v):
|
||||||
self._k_nets = v
|
self._k_nets = v
|
||||||
|
self.setTitle_(None)
|
||||||
config_changed()
|
config_changed()
|
||||||
def netsHidden(self):
|
def netsHidden(self):
|
||||||
#print 'checking netsHidden'
|
#print 'checking netsHidden'
|
||||||
@ -122,6 +143,8 @@ class SshuttleServer(NSObject):
|
|||||||
def setAutoNets_(self, v):
|
def setAutoNets_(self, v):
|
||||||
self._k_autoNets = v
|
self._k_autoNets = v
|
||||||
self.setNetsHidden_(-1)
|
self.setNetsHidden_(-1)
|
||||||
|
self.setUseDns_(v == NET_ALL)
|
||||||
|
self.setTitle_(None)
|
||||||
config_changed()
|
config_changed()
|
||||||
|
|
||||||
def autoHosts(self):
|
def autoHosts(self):
|
||||||
@ -129,3 +152,15 @@ class SshuttleServer(NSObject):
|
|||||||
def setAutoHosts_(self, v):
|
def setAutoHosts_(self, v):
|
||||||
self._k_autoHosts = v
|
self._k_autoHosts = v
|
||||||
config_changed()
|
config_changed()
|
||||||
|
|
||||||
|
def useDns(self):
|
||||||
|
return getattr(self, '_k_useDns', False)
|
||||||
|
def setUseDns_(self, v):
|
||||||
|
self._k_useDns = v
|
||||||
|
config_changed()
|
||||||
|
|
||||||
|
def latencyControl(self):
|
||||||
|
return getattr(self, '_k_latencyControl', LAT_INTERACTIVE)
|
||||||
|
def setLatencyControl_(self, v):
|
||||||
|
self._k_latencyControl = v
|
||||||
|
config_changed()
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
redo-ifchange debug.app
|
redo-ifchange debug.app
|
||||||
exec >&2
|
exec >&2
|
||||||
./debug.app/Contents/MacOS/run
|
./debug.app/Contents/MacOS/Sshuttle
|
||||||
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
pid = os.fork()
|
|
||||||
if pid == 0:
|
|
||||||
# child
|
|
||||||
try:
|
|
||||||
os.setsid()
|
|
||||||
#os.execvp('sudo', ['sudo', 'SSH_ASKPASS=%s' % os.path.abspath('askpass.py'), 'ssh', 'afterlife', 'ls'])
|
|
||||||
os.execvp('ssh', ['ssh', 'afterlife', 'ls'])
|
|
||||||
finally:
|
|
||||||
os._exit(44)
|
|
||||||
else:
|
|
||||||
# parent
|
|
||||||
os.wait()
|
|
Reference in New Issue
Block a user