PEP8 fixes.

This commit is contained in:
Brian May 2014-09-16 10:24:16 +10:00
parent 5529a04cc9
commit f1c79c7e92
16 changed files with 569 additions and 377 deletions

View File

@ -1,4 +1,5 @@
import sys, zlib import sys
import zlib
z = zlib.decompressobj() z = zlib.decompressobj()
mainmod = sys.modules[__name__] mainmod = sys.modules[__name__]

View File

@ -1,8 +1,17 @@
import struct, select, errno, re, signal, time import struct
import errno
import re
import signal
import time
import compat.ssubprocess as ssubprocess import compat.ssubprocess as ssubprocess
import helpers, ssnet, ssh, ssyslog import helpers
import os
import ssnet
import ssh
import ssyslog
import sys
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper
from helpers import * from helpers import log, debug1, debug2, debug3, Fatal, islocal
recvmsg = None recvmsg = None
try: try:
@ -23,6 +32,7 @@ except AttributeError:
_extra_fd = os.open('/dev/null', os.O_RDONLY) _extra_fd = os.open('/dev/null', os.O_RDONLY)
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)
@ -40,7 +50,8 @@ IPV6_RECVORIGDSTADDR = IPV6_ORIGDSTADDR
if recvmsg == "python": if recvmsg == "python":
def recv_udp(listener, bufsize): def recv_udp(listener, bufsize):
debug3('Accept UDP python using recvmsg.\n') debug3('Accept UDP python using recvmsg.\n')
data, ancdata, msg_flags, srcip = listener.recvmsg(4096,socket.CMSG_SPACE(24)) data, ancdata, msg_flags, srcip = listener.recvmsg(
4096, socket.CMSG_SPACE(24))
dstip = None dstip = None
family = None family = None
for cmsg_level, cmsg_type, cmsg_data in ancdata: for cmsg_level, cmsg_type, cmsg_data in ancdata:
@ -70,7 +81,8 @@ if recvmsg == "python":
elif recvmsg == "socket_ext": elif recvmsg == "socket_ext":
def recv_udp(listener, bufsize): def recv_udp(listener, bufsize):
debug3('Accept UDP using socket_ext recvmsg.\n') debug3('Accept UDP using socket_ext recvmsg.\n')
srcip, data, adata, flags = listener.recvmsg((bufsize,),socket.CMSG_SPACE(24)) srcip, data, adata, flags = listener.recvmsg(
(bufsize,), socket.CMSG_SPACE(24))
dstip = None dstip = None
family = None family = None
for a in adata: for a in adata:
@ -82,7 +94,8 @@ elif recvmsg == "socket_ext":
length = 4 length = 4
else: else:
raise Fatal("Unsupported socket type '%s'" % family) raise Fatal("Unsupported socket type '%s'" % family)
ip = socket.inet_ntop(family, a.cmsg_data[start:start+length]) ip = socket.inet_ntop(
family, a.cmsg_data[start:start + length])
dstip = (ip, port) dstip = (ip, port)
break break
elif a.cmsg_level == SOL_IPV6 and a.cmsg_type == IPV6_ORIGDSTADDR: elif a.cmsg_level == SOL_IPV6 and a.cmsg_type == IPV6_ORIGDSTADDR:
@ -93,7 +106,8 @@ elif recvmsg == "socket_ext":
length = 16 length = 16
else: else:
raise Fatal("Unsupported socket type '%s'" % family) raise Fatal("Unsupported socket type '%s'" % family)
ip = socket.inet_ntop(family, a.cmsg_data[start:start+length]) ip = socket.inet_ntop(
family, a.cmsg_data[start:start + length])
dstip = (ip, port) dstip = (ip, port)
break break
return (srcip, dstip, data[0]) return (srcip, dstip, data[0])
@ -201,9 +215,15 @@ class MultiListener:
def add_handler(self, handlers, callback, method, mux): def add_handler(self, handlers, callback, method, mux):
if self.v6: if self.v6:
handlers.append(Handler([self.v6], lambda: callback(self.v6, method, mux, handlers))) handlers.append(
Handler(
[self.v6],
lambda: callback(self.v6, method, mux, handlers)))
if self.v4: if self.v4:
handlers.append(Handler([self.v4], lambda: callback(self.v4, method, mux, handlers))) handlers.append(
Handler(
[self.v4],
lambda: callback(self.v4, method, mux, handlers)))
def listen(self, backlog): def listen(self, backlog):
if self.v6: if self.v6:
@ -239,7 +259,9 @@ class MultiListener:
class FirewallClient: class FirewallClient:
def __init__(self, port_v6, port_v4, subnets_include, subnets_exclude, dnsport_v6, dnsport_v4, method, udp):
def __init__(self, port_v6, port_v4, subnets_include, subnets_exclude,
dnsport_v6, dnsport_v4, method, udp):
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
@ -261,6 +283,7 @@ class FirewallClient:
# Instead, attach a *bidirectional* socket to its stdout, and use # Instead, attach a *bidirectional* socket to its stdout, and use
# that for talking in both directions. # that for talking in both directions.
(s1, s2) = socket.socketpair() (s1, s2) = socket.socketpair()
def setup(): def setup():
# run in the child process # run in the child process
s2.close() s2.close()
@ -321,6 +344,8 @@ class FirewallClient:
dnsreqs = {} dnsreqs = {}
udp_by_src = {} udp_by_src = {}
def expire_connections(now, mux): def expire_connections(now, mux):
for chan, timeout in dnsreqs.items(): for chan, timeout in dnsreqs.items():
if timeout < now: if timeout < now:
@ -355,7 +380,7 @@ def onaccept_tcp(listener, method, mux, handlers):
else: else:
raise raise
if method == "tproxy": if method == "tproxy":
dstip = sock.getsockname(); dstip = sock.getsockname()
else: else:
dstip = original_dst(sock) dstip = original_dst(sock)
debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0], srcip[1], debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0], srcip[1],
@ -369,7 +394,8 @@ def onaccept_tcp(listener, method, mux, handlers):
log('warning: too many open channels. Discarded connection.\n') log('warning: too many open channels. Discarded connection.\n')
sock.close() sock.close()
return return
mux.send(chan, ssnet.CMD_TCP_CONNECT, '%d,%s,%s' % (sock.family, dstip[0], dstip[1])) mux.send(chan, ssnet.CMD_TCP_CONNECT, '%d,%s,%s' %
(sock.family, dstip[0], dstip[1]))
outwrap = MuxWrapper(mux, chan) outwrap = MuxWrapper(mux, chan)
handlers.append(Proxy(SockWrapper(sock, sock), outwrap)) handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
expire_connections(time.time(), mux) expire_connections(time.time(), mux)
@ -395,14 +421,17 @@ def onaccept_udp(listener, method, mux, handlers):
now = time.time() now = time.time()
srcip, dstip, data = recv_udp(listener, 4096) srcip, dstip, data = recv_udp(listener, 4096)
if not dstip: if not dstip:
debug1("-- ignored UDP from %r: couldn't determine destination IP address\n" % (srcip,)) debug1(
"-- ignored UDP from %r: "
"couldn't determine destination IP address\n" % (srcip,))
return return
debug1('Accept UDP: %r -> %r.\n' % (srcip, dstip,)) debug1('Accept UDP: %r -> %r.\n' % (srcip, dstip,))
if srcip in udp_by_src: if srcip in udp_by_src:
chan, timeout = udp_by_src[srcip] chan, timeout = udp_by_src[srcip]
else: else:
chan = mux.next_channel() chan = mux.next_channel()
mux.channels[chan] = lambda cmd,data: udp_done(chan, data, method, listener.family, dstip=srcip) mux.channels[chan] = lambda cmd, data: udp_done(
chan, data, method, listener.family, dstip=srcip)
mux.send(chan, ssnet.CMD_UDP_OPEN, listener.family) mux.send(chan, ssnet.CMD_UDP_OPEN, listener.family)
udp_by_src[srcip] = chan, now + 30 udp_by_src[srcip] = chan, now + 30
@ -433,17 +462,21 @@ def ondns(listener, method, mux, handlers):
now = time.time() now = time.time()
srcip, dstip, data = recv_udp(listener, 4096) srcip, dstip, data = recv_udp(listener, 4096)
if method == "tproxy" and not dstip: if method == "tproxy" and not dstip:
debug1("-- ignored UDP from %r: couldn't determine destination IP address\n" % (srcip,)) debug1(
"-- ignored UDP from %r: "
"couldn't determine destination IP address\n" % (srcip,))
return return
debug1('DNS request from %r to %r: %d bytes\n' % (srcip, dstip, len(data))) debug1('DNS request from %r to %r: %d bytes\n' % (srcip, dstip, len(data)))
chan = mux.next_channel() chan = mux.next_channel()
dnsreqs[chan] = now + 30 dnsreqs[chan] = now + 30
mux.send(chan, ssnet.CMD_DNS_REQ, data) mux.send(chan, ssnet.CMD_DNS_REQ, data)
mux.channels[chan] = lambda cmd,data: dns_done(chan, data, method, listener, srcip=dstip, dstip=srcip, mux=mux) mux.channels[chan] = lambda cmd, data: dns_done(
chan, data, method, listener, srcip=dstip, dstip=srcip, mux=mux)
expire_connections(now, mux) expire_connections(now, mux)
def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, python, latency_control, def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename,
python, latency_control,
dns_listener, method, seed_hosts, auto_nets, dns_listener, method, seed_hosts, auto_nets,
syslog, daemon): syslog, daemon):
handlers = [] handlers = []
@ -454,7 +487,8 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, python, latency_c
debug1('connecting to server...\n') debug1('connecting to server...\n')
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, method=method)) options=dict(latency_control=latency_control, method=method))
except socket.error, e: except socket.error, e:
@ -531,7 +565,7 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, python, latency_c
if dns_listener: if dns_listener:
dns_listener.add_handler(handlers, ondns, method, mux) dns_listener.add_handler(handlers, ondns, method, mux)
if seed_hosts != None: if seed_hosts is not 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))
@ -684,20 +718,23 @@ def main(listenip_v6, listenip_v4,
dnsport_v4 = 0 dnsport_v4 = 0
dns_listener = None dns_listener = None
fw = FirewallClient(redirectport_v6, redirectport_v4, subnets_include, subnets_exclude, dnsport_v6, dnsport_v4, method, udp) fw = FirewallClient(redirectport_v6, redirectport_v4, subnets_include,
subnets_exclude, dnsport_v6, dnsport_v4, method, udp)
if fw.method == "tproxy": if fw.method == "tproxy":
tcp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1) tcp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1)
if udp_listener: if udp_listener:
udp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1) udp_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1)
if udp_listener.v4 is not None: if udp_listener.v4 is not None:
udp_listener.v4.setsockopt(socket.SOL_IP, IP_RECVORIGDSTADDR, 1) udp_listener.v4.setsockopt(
socket.SOL_IP, IP_RECVORIGDSTADDR, 1)
if udp_listener.v6 is not None: if udp_listener.v6 is not None:
udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1) udp_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1)
if dns_listener: if dns_listener:
dns_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1) dns_listener.setsockopt(socket.SOL_IP, IP_TRANSPARENT, 1)
if dns_listener.v4 is not None: if dns_listener.v4 is not None:
dns_listener.v4.setsockopt(socket.SOL_IP, IP_RECVORIGDSTADDR, 1) dns_listener.v4.setsockopt(
socket.SOL_IP, IP_RECVORIGDSTADDR, 1)
if dns_listener.v6 is not None: if dns_listener.v6 is not None:
dns_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1) dns_listener.v6.setsockopt(SOL_IPV6, IPV6_RECVORIGDSTADDR, 1)

View File

@ -1,7 +1,13 @@
import re, errno, socket, select, struct import errno
import socket
import select
import struct
import compat.ssubprocess as ssubprocess import compat.ssubprocess as ssubprocess
import helpers, ssyslog import ssyslog
from helpers import * import sys
import os
from helpers import log, debug1, debug3, islocal, Fatal, family_to_string, \
resolvconf_nameservers
# python doesn't have a definition for this # python doesn't have a definition for this
IPPROTO_DIVERT = 254 IPPROTO_DIVERT = 254
@ -45,6 +51,8 @@ def _ipt(family, table, *args):
_no_ttl_module = False _no_ttl_module = False
def _ipt_ttl(family, *args): def _ipt_ttl(family, *args):
global _no_ttl_module global _no_ttl_module
if not _no_ttl_module: if not _no_ttl_module:
@ -72,13 +80,17 @@ def _ipt_ttl(family, *args):
def do_iptables_nat(port, dnsport, family, subnets, udp): def do_iptables_nat(port, dnsport, family, subnets, udp):
# only ipv4 supported with NAT # only ipv4 supported with NAT
if family != socket.AF_INET: if family != socket.AF_INET:
raise Exception('Address family "%s" unsupported by nat method'%family_to_string(family)) raise Exception(
'Address family "%s" unsupported by nat method'
% family_to_string(family))
if udp: if udp:
raise Exception("UDP not supported by nat method") raise Exception("UDP not supported by nat method")
table = "nat" table = "nat"
def ipt(*args): def ipt(*args):
return _ipt(family, table, *args) return _ipt(family, table, *args)
def ipt_ttl(*args): def ipt_ttl(*args):
return _ipt_ttl(family, table, *args) return _ipt_ttl(family, table, *args)
@ -103,7 +115,8 @@ def do_iptables_nat(port, dnsport, family, subnets, udp):
# to least-specific, and at any given level of specificity, we want # to least-specific, and at any given level of specificity, we want
# excludes to come first. That's why the columns are in such a non- # excludes to come first. That's why the columns are in such a non-
# intuitive order. # intuitive order.
for f,swidth,sexclude,snet in sorted(subnets, key=lambda s: s[1], reverse=True): for f, swidth, sexclude, snet \
in sorted(subnets, key=lambda s: s[1], reverse=True):
if sexclude: if sexclude:
ipt('-A', chain, '-j', 'RETURN', ipt('-A', chain, '-j', 'RETURN',
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
@ -126,11 +139,15 @@ def do_iptables_nat(port, dnsport, family, subnets, udp):
def do_iptables_tproxy(port, dnsport, family, subnets, udp): def do_iptables_tproxy(port, dnsport, family, subnets, udp):
if family not in [socket.AF_INET, socket.AF_INET6]: if family not in [socket.AF_INET, socket.AF_INET6]:
raise Exception('Address family "%s" unsupported by tproxy method'%family_to_string(family)) raise Exception(
'Address family "%s" unsupported by tproxy method'
% family_to_string(family))
table = "mangle" table = "mangle"
def ipt(*args): def ipt(*args):
return _ipt(family, table, *args) return _ipt(family, table, *args)
def ipt_ttl(*args): def ipt_ttl(*args):
return _ipt_ttl(family, table, *args) return _ipt_ttl(family, table, *args)
@ -182,7 +199,8 @@ def do_iptables_tproxy(port, dnsport, family, subnets, udp):
'--on-port', str(dnsport)) '--on-port', str(dnsport))
if subnets: if subnets:
for f,swidth,sexclude,snet in sorted(subnets, key=lambda s: s[1], reverse=True): for f, swidth, sexclude, snet \
in sorted(subnets, key=lambda s: s[1], reverse=True):
if sexclude: if sexclude:
ipt('-A', mark_chain, '-j', 'RETURN', ipt('-A', mark_chain, '-j', 'RETURN',
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
@ -191,10 +209,12 @@ def do_iptables_tproxy(port, dnsport, family, subnets, udp):
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
'-m', 'tcp', '-p', 'tcp') '-m', 'tcp', '-p', 'tcp')
else: else:
ipt('-A', mark_chain, '-j', 'MARK', '--set-mark', '1', ipt('-A', mark_chain, '-j', 'MARK',
'--set-mark', '1',
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
'-m', 'tcp', '-p', 'tcp') '-m', 'tcp', '-p', 'tcp')
ipt('-A', tproxy_chain, '-j', 'TPROXY', '--tproxy-mark', '0x1/0x1', ipt('-A', tproxy_chain, '-j', 'TPROXY',
'--tproxy-mark', '0x1/0x1',
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
'-m', 'tcp', '-p', 'tcp', '-m', 'tcp', '-p', 'tcp',
'--on-port', str(port)) '--on-port', str(port))
@ -207,10 +227,12 @@ def do_iptables_tproxy(port, dnsport, family, subnets, udp):
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
'-m', 'udp', '-p', 'udp') '-m', 'udp', '-p', 'udp')
elif udp: elif udp:
ipt('-A', mark_chain, '-j', 'MARK', '--set-mark', '1', ipt('-A', mark_chain, '-j', 'MARK',
'--set-mark', '1',
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
'-m', 'udp', '-p', 'udp') '-m', 'udp', '-p', 'udp')
ipt('-A', tproxy_chain, '-j', 'TPROXY', '--tproxy-mark', '0x1/0x1', ipt('-A', tproxy_chain, '-j', 'TPROXY',
'--tproxy-mark', '0x1/0x1',
'--dest', '%s/%s' % (snet, swidth), '--dest', '%s/%s' % (snet, swidth),
'-m', 'udp', '-p', 'udp', '-m', 'udp', '-p', 'udp',
'--on-port', str(port)) '--on-port', str(port))
@ -235,6 +257,8 @@ def ipfw_rule_exists(n):
_oldctls = {} _oldctls = {}
def _fill_oldctls(prefix): def _fill_oldctls(prefix):
argv = ['sysctl', prefix] argv = ['sysctl', prefix]
p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE) p = ssubprocess.Popen(argv, stdout=ssubprocess.PIPE)
@ -256,6 +280,8 @@ def _sysctl_set(name, val):
_changedctls = [] _changedctls = []
def sysctl_set(name, val, permanent=False): def sysctl_set(name, val, permanent=False):
PREFIX = 'net.inet.ip' PREFIX = 'net.inet.ip'
assert(name.startswith(PREFIX + '.')) assert(name.startswith(PREFIX + '.'))
@ -293,6 +319,8 @@ def _udp_repack(p, src, dst):
_real_dns_server = [None] _real_dns_server = [None]
def _handle_diversion(divertsock, dnsport): def _handle_diversion(divertsock, dnsport):
p, tag = divertsock.recvfrom(4096) p, tag = divertsock.recvfrom(4096)
src, dst = _udp_unpack(p) src, dst = _udp_unpack(p)
@ -324,7 +352,9 @@ def ipfw(*args):
def do_ipfw(port, dnsport, family, subnets, udp): def do_ipfw(port, dnsport, family, subnets, udp):
# IPv6 not supported # IPv6 not supported
if family not in [socket.AF_INET, ]: if family not in [socket.AF_INET, ]:
raise Exception('Address family "%s" unsupported by ipfw method'%family_to_string(family)) raise Exception(
'Address family "%s" unsupported by ipfw method'
% family_to_string(family))
if udp: if udp:
raise Exception("UDP not supported by ipfw method") raise Exception("UDP not supported by ipfw method")
@ -360,7 +390,8 @@ def do_ipfw(port, dnsport, family, subnets, udp):
if subnets: if subnets:
# create new subnet entries # create new subnet entries
for f,swidth,sexclude,snet in sorted(subnets, key=lambda s: s[1], reverse=True): for f, swidth, sexclude, snet \
in sorted(subnets, key=lambda s: s[1], reverse=True):
if sexclude: if sexclude:
ipfw('add', sport, 'skipto', xsport, ipfw('add', sport, 'skipto', xsport,
'log', 'tcp', 'log', 'tcp',
@ -440,6 +471,8 @@ def program_exists(name):
hostmap = {} hostmap = {}
def rewrite_etc_hosts(port): def rewrite_etc_hosts(port):
HOSTSFILE = '/etc/hosts' HOSTSFILE = '/etc/hosts'
BAKFILE = '%s.sbak' % HOSTSFILE BAKFILE = '%s.sbak' % HOSTSFILE
@ -564,13 +597,15 @@ def main(port_v6, port_v4, dnsport_v6, dnsport_v4, method, udp, syslog):
subnets_v6 = filter(lambda i: i[0] == socket.AF_INET6, subnets) subnets_v6 = filter(lambda i: i[0] == socket.AF_INET6, subnets)
if port_v6: if port_v6:
do_wait = do_it(port_v6, dnsport_v6, socket.AF_INET6, subnets_v6, udp) do_wait = do_it(
port_v6, dnsport_v6, socket.AF_INET6, subnets_v6, udp)
elif len(subnets_v6) > 0: elif len(subnets_v6) > 0:
debug1("IPv6 subnets defined but IPv6 disabled\n") debug1("IPv6 subnets defined but IPv6 disabled\n")
subnets_v4 = filter(lambda i: i[0] == socket.AF_INET, subnets) subnets_v4 = filter(lambda i: i[0] == socket.AF_INET, subnets)
if port_v4: if port_v4:
do_wait = do_it(port_v4, dnsport_v4, socket.AF_INET, subnets_v4, udp) do_wait = do_it(
port_v4, dnsport_v4, socket.AF_INET, subnets_v4, udp)
elif len(subnets_v4) > 0: elif len(subnets_v4) > 0:
debug1('IPv4 subnets defined but IPv4 disabled\n') debug1('IPv4 subnets defined but IPv4 disabled\n')
@ -587,7 +622,8 @@ def main(port_v6, port_v4, dnsport_v6, dnsport_v4, method, udp, 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() 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)

View File

@ -1,8 +1,11 @@
import sys, os, socket, errno import sys
import socket
import errno
logprefix = '' logprefix = ''
verbose = 0 verbose = 0
def log(s): def log(s):
try: try:
sys.stdout.flush() sys.stdout.flush()
@ -13,14 +16,17 @@ def log(s):
# our tty closes. That sucks, but it's no reason to abort the program. # our tty closes. That sucks, but it's no reason to abort the program.
pass pass
def debug1(s): def debug1(s):
if verbose >= 1: if verbose >= 1:
log(s) log(s)
def debug2(s): def debug2(s):
if verbose >= 2: if verbose >= 2:
log(s) log(s)
def debug3(s): def debug3(s):
if verbose >= 3: if verbose >= 3:
log(s) log(s)
@ -83,4 +89,3 @@ def family_to_string(family):
return "AF_INET" return "AF_INET"
else: else:
return str(family) return str(family)

View File

@ -1,8 +1,14 @@
import time, socket, re, select, errno import time
import socket
import re
import select
import errno
import os
import sys
if not globals().get('skip_imports'): if not globals().get('skip_imports'):
import compat.ssubprocess as ssubprocess import compat.ssubprocess as ssubprocess
import helpers import helpers
from helpers import * from helpers import log, debug1, debug2, debug3
POLL_TIME = 60 * 15 POLL_TIME = 60 * 15
NETSTAT_POLL_TIME = 30 NETSTAT_POLL_TIME = 30
@ -94,7 +100,7 @@ def _check_revdns(ip):
debug3('< %s\n' % r[0]) debug3('< %s\n' % r[0])
check_host(r[0]) check_host(r[0])
found_host(r[0], ip) found_host(r[0], ip)
except socket.herror, e: except socket.herror:
pass pass
@ -105,7 +111,7 @@ def _check_dns(hostname):
debug3('< %s\n' % ip) debug3('< %s\n' % ip)
check_host(ip) check_host(ip)
found_host(hostname, ip) found_host(hostname, ip)
except socket.gaierror, e: except socket.gaierror:
pass pass
@ -229,7 +235,7 @@ def check_workgroup(hostname):
def _enqueue(op, *args): def _enqueue(op, *args):
t = (op, args) t = (op, args)
if queue.get(t) == None: if queue.get(t) is None:
queue[t] = 0 queue[t] = 0

View File

@ -1,7 +1,13 @@
import sys, os, re, socket import sys
import helpers, options, client, server, firewall, hostwatch import re
import compat.ssubprocess as ssubprocess import socket
from helpers import * import helpers
import options
import client
import server
import firewall
import hostwatch
from helpers import log, Fatal
# 1.2.3.4/5 or just 1.2.3.4 # 1.2.3.4/5 or just 1.2.3.4
@ -11,7 +17,7 @@ def parse_subnet4(s):
raise Fatal('%r is not a valid IP subnet format' % s) raise Fatal('%r is not a valid IP subnet format' % s)
(a, b, c, d, width) = m.groups() (a, b, c, d, width) = m.groups()
(a, b, c, d) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0)) (a, b, c, d) = (int(a or 0), int(b or 0), int(c or 0), int(d or 0))
if width == None: if width is None:
width = 32 width = 32
else: else:
width = int(width) width = int(width)
@ -28,7 +34,7 @@ def parse_subnet6(s):
if not m: if not m:
raise Fatal('%r is not a valid IP subnet format' % s) raise Fatal('%r is not a valid IP subnet format' % s)
(net, width) = m.groups() (net, width) = m.groups()
if width == None: if width is None:
width = 128 width = 128
else: else:
width = int(width) width = int(width)
@ -41,7 +47,7 @@ def parse_subnet6(s):
def parse_subnet_file(s): def parse_subnet_file(s):
try: try:
handle = open(s, 'r') handle = open(s, 'r')
except OSError, e: except OSError:
raise Fatal('Unable to open subnet file: %s' % s) raise Fatal('Unable to open subnet file: %s' % s)
raw_config_lines = handle.readlines() raw_config_lines = handle.readlines()
@ -84,7 +90,7 @@ def parse_ipport4(s):
raise Fatal('%d.%d.%d.%d has numbers > 255' % (a, b, c, d)) raise Fatal('%d.%d.%d.%d has numbers > 255' % (a, b, c, d))
if port > 65535: if port > 65535:
raise Fatal('*:%d is greater than the maximum of 65535' % port) raise Fatal('*:%d is greater than the maximum of 65535' % port)
if a == None: if a is None:
a = b = c = d = 0 a = b = c = d = 0
return ('%d.%d.%d.%d' % (a, b, c, d), port) return ('%d.%d.%d.%d' % (a, b, c, d), port)

View File

@ -1,9 +1,16 @@
"""Command-line options parser. """Command-line options parser.
With the help of an options spec string, easily parse command-line options. With the help of an options spec string, easily parse command-line options.
""" """
import sys, os, textwrap, getopt, re, struct import sys
import os
import textwrap
import getopt
import re
import struct
class OptDict: class OptDict:
def __init__(self): def __init__(self):
self._opts = {} self._opts = {}
@ -48,6 +55,7 @@ def _remove_negative_kv(k, v):
return k[3:], not v return k[3:], not v
return k, v return k, v
def _remove_negative_k(k): def _remove_negative_k(k):
return _remove_negative_kv(k, None)[0] return _remove_negative_kv(k, None)[0]
@ -55,7 +63,8 @@ def _remove_negative_k(k):
def _tty_width(): def _tty_width():
s = struct.pack("HHHH", 0, 0, 0, 0) s = struct.pack("HHHH", 0, 0, 0, 0)
try: try:
import fcntl, termios import fcntl
import termios
s = fcntl.ioctl(sys.stderr.fileno(), termios.TIOCGWINSZ, s) s = fcntl.ioctl(sys.stderr.fileno(), termios.TIOCGWINSZ, s)
except (IOError, ImportError): except (IOError, ImportError):
return _atoi(os.environ.get('WIDTH')) or 70 return _atoi(os.environ.get('WIDTH')) or 70
@ -64,6 +73,7 @@ def _tty_width():
class Options: class Options:
"""Option parser. """Option parser.
When constructed, two strings are mandatory. The first one is the command When constructed, two strings are mandatory. The first one is the command
name showed before error messages. The second one is a string called an name showed before error messages. The second one is a string called an
@ -76,6 +86,7 @@ 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, optspec, optfunc=getopt.gnu_getopt, def __init__(self, optspec, optfunc=getopt.gnu_getopt,
onabort=_default_onabort): onabort=_default_onabort):
self.optspec = optspec self.optspec = optspec
@ -95,7 +106,8 @@ class Options:
first_syn = True first_syn = True
while lines: while lines:
l = lines.pop() l = lines.pop()
if l == '--': break if l == '--':
break
out.append('%s: %s\n' % (first_syn and 'usage' or ' or', l)) out.append('%s: %s\n' % (first_syn and 'usage' or ' or', l))
first_syn = False first_syn = False
out.append('\n') out.append('\n')
@ -170,7 +182,8 @@ class Options:
and "extra" is a list of positional arguments. and "extra" is a list of positional arguments.
""" """
try: try:
(flags,extra) = self.optfunc(args, self._shortopts, self._longopts) (flags, extra) = self.optfunc(
args, self._shortopts, self._longopts)
except getopt.GetoptError, e: except getopt.GetoptError, e:
self.fatal(e) self.fatal(e)

View File

@ -1,9 +1,22 @@
import re, struct, socket, select, traceback, time import re
import struct
import socket
import traceback
import time
import sys
import os
if not globals().get('skip_imports'): if not globals().get('skip_imports'):
import ssnet, helpers, hostwatch import ssnet
import helpers
import hostwatch
import compat.ssubprocess as ssubprocess import compat.ssubprocess as ssubprocess
from ssnet import SockWrapper, Handler, Proxy, Mux, MuxWrapper from ssnet import Handler, Proxy, Mux, MuxWrapper
from helpers import * from helpers import log, debug1, debug2, debug3, Fatal, \
resolvconf_random_nameserver
if not globals().get('latency_control'):
latency_control = None
def _ipmatch(ipstr): def _ipmatch(ipstr):
@ -14,13 +27,13 @@ def _ipmatch(ipstr):
g = m.groups() g = m.groups()
ips = g[0] ips = g[0]
width = int(g[4] or 32) width = int(g[4] or 32)
if g[1] == None: if g[1] is None:
ips += '.0.0.0' ips += '.0.0.0'
width = min(width, 8) width = min(width, 8)
elif g[2] == None: elif g[2] is None:
ips += '.0.0' ips += '.0.0'
width = min(width, 16) width = min(width, 16)
elif g[3] == None: elif g[3] is None:
ips += '.0' ips += '.0'
width = min(width, 24) width = min(width, 24)
return (struct.unpack('!I', socket.inet_aton(ips))[0], width) return (struct.unpack('!I', socket.inet_aton(ips))[0], width)
@ -59,7 +72,8 @@ def _list_routes():
mask = _maskbits(maskw) # returns 32 if maskw is null mask = _maskbits(maskw) # returns 32 if maskw is null
width = min(ipw[1], mask) width = min(ipw[1], mask)
ip = ipw[0] & _shl(_shl(1, width) - 1, 32 - width) ip = ipw[0] & _shl(_shl(1, width) - 1, 32 - width)
routes.append((socket.AF_INET, socket.inet_ntoa(struct.pack('!I', ip)), width)) routes.append(
(socket.AF_INET, socket.inet_ntoa(struct.pack('!I', ip)), width))
rv = p.wait() rv = p.wait()
if rv != 0: if rv != 0:
log('WARNING: %r returned %d\n' % (argv, rv)) log('WARNING: %r returned %d\n' % (argv, rv))
@ -91,7 +105,7 @@ def start_hostwatch(seed_hosts):
os.dup2(s1.fileno(), 0) os.dup2(s1.fileno(), 0)
s1.close() s1.close()
rv = hostwatch.hw_main(seed_hosts) or 0 rv = hostwatch.hw_main(seed_hosts) or 0
except Exception, e: except Exception:
log('%s\n' % _exc_dump()) log('%s\n' % _exc_dump())
rv = 98 rv = 98
finally: finally:
@ -101,12 +115,14 @@ def start_hostwatch(seed_hosts):
class Hostwatch: class Hostwatch:
def __init__(self): def __init__(self):
self.pid = 0 self.pid = 0
self.sock = None self.sock = None
class DnsProxy(Handler): class DnsProxy(Handler):
def __init__(self, mux, chan, request): def __init__(self, mux, chan, request):
# FIXME! IPv4 specific # FIXME! IPv4 specific
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
@ -164,6 +180,7 @@ class DnsProxy(Handler):
class UdpProxy(Handler): class UdpProxy(Handler):
def __init__(self, mux, chan, family): def __init__(self, mux, chan, family):
sock = socket.socket(family, socket.SOCK_DGRAM) sock = socket.socket(family, socket.SOCK_DGRAM)
Handler.__init__(self, [sock]) Handler.__init__(self, [sock])
@ -192,11 +209,13 @@ class UdpProxy(Handler):
hdr = "%s,%r," % (peer[0], peer[1]) hdr = "%s,%r," % (peer[0], peer[1])
self.mux.send(self.chan, ssnet.CMD_UDP_DATA, hdr + data) self.mux.send(self.chan, ssnet.CMD_UDP_DATA, hdr + data)
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: '
assert latency_control is not None
debug1('latency control setting = %r\n' % latency_control) debug1('latency control setting = %r\n' % latency_control)
routes = list(list_routes()) routes = list(list_routes())
@ -253,6 +272,7 @@ def main():
mux.new_channel = new_channel mux.new_channel = new_channel
dnshandlers = {} dnshandlers = {}
def dns_req(channel, data): def dns_req(channel, data):
debug2('Incoming DNS request channel=%d.\n' % channel) debug2('Incoming DNS request channel=%d.\n' % channel)
h = DnsProxy(mux, channel, data) h = DnsProxy(mux, channel, data)
@ -261,6 +281,7 @@ def main():
mux.got_dns_req = dns_req mux.got_dns_req = dns_req
udphandlers = {} udphandlers = {}
def udp_req(channel, cmd, data): def udp_req(channel, cmd, data):
debug2('Incoming UDP request channel=%d, cmd=%d\n' % (channel, cmd)) debug2('Incoming UDP request channel=%d, cmd=%d\n' % (channel, cmd))
if cmd == ssnet.CMD_UDP_DATA: if cmd == ssnet.CMD_UDP_DATA:
@ -287,13 +308,13 @@ def main():
udphandlers[channel] = h udphandlers[channel] = h
mux.got_udp_open = udp_open mux.got_udp_open = udp_open
while mux.ok: while mux.ok:
if hw.pid: if hw.pid:
assert(hw.pid > 0) assert(hw.pid > 0)
(rpid, rv) = os.waitpid(hw.pid, os.WNOHANG) (rpid, rv) = os.waitpid(hw.pid, os.WNOHANG)
if rpid: if rpid:
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: if latency_control:

View File

@ -1,7 +1,11 @@
import sys, os, re, socket, zlib import sys
import os
import re
import socket
import zlib
import compat.ssubprocess as ssubprocess import compat.ssubprocess as ssubprocess
import helpers import helpers
from helpers import * from helpers import debug2
def readfile(name): def readfile(name):
@ -24,7 +28,6 @@ def empackage(z, filename, data=None):
def connect(ssh_cmd, rhostport, python, stderr, options): def connect(ssh_cmd, rhostport, python, stderr, options):
main_exe = sys.argv[0]
portl = [] portl = []
if (rhostport or '').count(':') > 1: if (rhostport or '').count(':') > 1:
@ -35,7 +38,9 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
result[1] = result[1].strip(':') result[1] = result[1].strip(':')
if result[1] is not '': if result[1] is not '':
portl = ['-p', str(int(result[1]))] portl = ['-p', str(int(result[1]))]
else: # can't disambiguate IPv6 colons and a port number. pass the hostname through. # can't disambiguate IPv6 colons and a port number. pass the hostname
# through.
else:
rhost = rhostport rhost = rhostport
else: # IPv4 else: # IPv4
l = (rhostport or '').split(':', 1) l = (rhostport or '').split(':', 1)
@ -65,7 +70,6 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
""" % (helpers.verbose or 0, len(content)) """ % (helpers.verbose or 0, len(content))
pyscript = re.sub(r'\s+', ' ', pyscript.strip()) pyscript = re.sub(r'\s+', ' ', pyscript.strip())
if not rhost: if not rhost:
# ignore the --python argument when running locally; we already know # ignore the --python argument when running locally; we already know
# which python version works. # which python version works.
@ -84,6 +88,7 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
portl + portl +
[rhost, '--', pycmd]) [rhost, '--', pycmd])
(s1, s2) = socket.socketpair() (s1, s2) = socket.socketpair()
def setup(): def setup():
# runs in the child process # runs in the child process
s2.close() s2.close()

View File

@ -1,6 +1,10 @@
import struct, socket, errno, select import struct
import socket
import errno
import select
import os
if not globals().get('skip_imports'): if not globals().get('skip_imports'):
from helpers import * from helpers import log, debug1, debug2, debug3, Fatal
MAX_CHANNEL = 65535 MAX_CHANNEL = 65535
@ -92,7 +96,10 @@ def _try_peername(sock):
_swcount = 0 _swcount = 0
class SockWrapper: class SockWrapper:
def __init__(self, rsock, wsock, connect_to=None, peername=None): def __init__(self, rsock, wsock, connect_to=None, peername=None):
global _swcount global _swcount
_swcount += 1 _swcount += 1
@ -243,6 +250,7 @@ class SockWrapper:
class Handler: class Handler:
def __init__(self, socks=None, callback=None): def __init__(self, socks=None, callback=None):
self.ok = True self.ok = True
self.socks = socks or [] self.socks = socks or []
@ -265,6 +273,7 @@ class Handler:
class Proxy(Handler): class Proxy(Handler):
def __init__(self, wrap1, wrap2): def __init__(self, wrap1, wrap2):
Handler.__init__(self, [wrap1.rsock, wrap1.wsock, Handler.__init__(self, [wrap1.rsock, wrap1.wsock,
wrap2.rsock, wrap2.wsock]) wrap2.rsock, wrap2.wsock])
@ -272,8 +281,10 @@ class Proxy(Handler):
self.wrap2 = wrap2 self.wrap2 = wrap2
def pre_select(self, r, w, x): def pre_select(self, r, w, x):
if self.wrap1.shut_write: self.wrap2.noread() if self.wrap1.shut_write:
if self.wrap2.shut_write: self.wrap1.noread() self.wrap2.noread()
if self.wrap2.shut_write:
self.wrap1.noread()
if self.wrap1.connect_to: if self.wrap1.connect_to:
_add(w, self.wrap1.rsock) _add(w, self.wrap1.rsock)
@ -312,6 +323,7 @@ class Proxy(Handler):
class Mux(Handler): class Mux(Handler):
def __init__(self, rsock, wsock): def __init__(self, rsock, wsock):
Handler.__init__(self, [rsock, wsock]) Handler.__init__(self, [rsock, wsock])
self.rsock = rsock self.rsock = rsock
@ -465,6 +477,7 @@ class Mux(Handler):
class MuxWrapper(SockWrapper): class MuxWrapper(SockWrapper):
def __init__(self, mux, channel): def __init__(self, mux, channel):
SockWrapper.__init__(self, mux.rsock, mux.wsock) SockWrapper.__init__(self, mux.rsock, mux.wsock)
self.mux = mux self.mux = mux

View File

@ -1,8 +1,11 @@
import sys, os import sys
import os
from compat import ssubprocess from compat import ssubprocess
_p = None _p = None
def start_syslog(): def start_syslog():
global _p global _p
_p = ssubprocess.Popen(['logger', _p = ssubprocess.Popen(['logger',

View File

@ -1,5 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys, os, socket, select, struct, time import socket
import select
import struct
import time
listener = socket.socket() listener = socket.socket()
listener.bind(('127.0.0.1', 0)) listener.bind(('127.0.0.1', 0))

View File

@ -1,4 +1,6 @@
import sys, os, re, subprocess import re
import subprocess
def askpass(prompt): def askpass(prompt):
prompt = prompt.replace('"', "'") prompt = prompt.replace('"', "'")

View File

@ -1,6 +1,11 @@
import sys, os, pty import sys
import os
import pty
from AppKit import * from AppKit import *
import my, models, askpass import my
import models
import askpass
def sshuttle_args(host, auto_nets, auto_hosts, dns, nets, debug, def sshuttle_args(host, auto_nets, auto_hosts, dns, nets, debug,
no_latency_control): no_latency_control):
@ -21,21 +26,25 @@ def sshuttle_args(host, auto_nets, auto_hosts, dns, nets, debug,
class _Callback(NSObject): class _Callback(NSObject):
def initWithFunc_(self, func): def initWithFunc_(self, func):
self = super(_Callback, self).init() self = super(_Callback, self).init()
self.func = func self.func = func
return self return self
def func_(self, obj): def func_(self, obj):
return self.func(obj) return self.func(obj)
class Callback: class Callback:
def __init__(self, func): def __init__(self, func):
self.obj = _Callback.alloc().initWithFunc_(func) self.obj = _Callback.alloc().initWithFunc_(func)
self.sel = self.obj.func_ self.sel = self.obj.func_
class Runner: class Runner:
def __init__(self, argv, logfunc, promptfunc, serverobj): def __init__(self, argv, logfunc, promptfunc, serverobj):
print 'in __init__' print 'in __init__'
self.id = argv self.id = argv
@ -65,7 +74,8 @@ class Runner:
.initWithFileDescriptor_closeOnDealloc_(fd, True) .initWithFileDescriptor_closeOnDealloc_(fd, True)
self.cb = Callback(self.gotdata) self.cb = Callback(self.gotdata)
NSNotificationCenter.defaultCenter()\ NSNotificationCenter.defaultCenter()\
.addObserver_selector_name_object_(self.cb.obj, self.cb.sel, .addObserver_selector_name_object_(
self.cb.obj, self.cb.sel,
NSFileHandleDataAvailableNotification, self.file) NSFileHandleDataAvailableNotification, self.file)
self.file.waitForDataInBackgroundAndNotify() self.file.waitForDataInBackgroundAndNotify()
@ -73,7 +83,7 @@ class Runner:
self.wait() self.wait()
def _try_wait(self, options): def _try_wait(self, options):
if self.rv == None and self.pid > 0: if self.rv is None and self.pid > 0:
pid, code = os.waitpid(self.pid, options) pid, code = os.waitpid(self.pid, options)
if pid == self.pid: if pid == self.pid:
if os.WIFEXITED(code): if os.WIFEXITED(code):
@ -95,7 +105,7 @@ class Runner:
def kill(self): def kill(self):
assert(self.pid > 0) assert(self.pid > 0)
print 'killing: pid=%r rv=%r' % (self.pid, self.rv) print 'killing: pid=%r rv=%r' % (self.pid, self.rv)
if self.rv == None: if self.rv is None:
self.logfunc('Disconnecting from %s.\n' % self.serverobj.host()) self.logfunc('Disconnecting from %s.\n' % self.serverobj.host())
os.kill(self.pid, 15) os.kill(self.pid, 15)
self.wait() self.wait()
@ -122,6 +132,7 @@ class Runner:
class SshuttleApp(NSObject): class SshuttleApp(NSObject):
def initialize(self): def initialize(self):
d = my.PList('UserDefaults') d = my.PList('UserDefaults')
my.Defaults().registerDefaults_(d) my.Defaults().registerDefaults_(d)
@ -145,12 +156,14 @@ class SshuttleController(NSObject):
host = server.host() host = server.host()
print 'connecting %r' % host print 'connecting %r' % host
self.fill_menu() self.fill_menu()
def logfunc(msg): def logfunc(msg):
print 'log! (%d bytes)' % len(msg) print 'log! (%d bytes)' % len(msg)
self.logField.textStorage()\ self.logField.textStorage()\
.appendAttributedString_(NSAttributedString.alloc()\ .appendAttributedString_(NSAttributedString.alloc()
.initWithString_(msg)) .initWithString_(msg))
self.logField.didChangeText() self.logField.didChangeText()
def promptfunc(prompt): def promptfunc(prompt):
print 'prompt! %r' % prompt print 'prompt! %r' % prompt
return askpass.askpass(prompt) return askpass.askpass(prompt)
@ -213,6 +226,7 @@ class SshuttleController(NSObject):
it.setRepresentedObject_(obj) it.setRepresentedObject_(obj)
it.setTarget_(self) it.setTarget_(self)
it.setAction_(func) it.setAction_(func)
def addnote(name): def addnote(name):
additem(name, None, None) additem(name, None, None)
@ -271,7 +285,8 @@ class SshuttleController(NSObject):
sl = [] sl = []
for s in l: for s in l:
host = s.get('host', None) host = s.get('host', None)
if not host: continue if not host:
continue
nets = s.get('nets', []) nets = s.get('nets', [])
nl = [] nl = []
@ -302,11 +317,13 @@ class SshuttleController(NSObject):
l = [] l = []
for s in self.servers: for s in self.servers:
host = s.host() host = s.host()
if not host: continue if not host:
continue
nets = [] nets = []
for n in s.nets(): for n in s.nets():
subnet = n.subnet() subnet = n.subnet()
if not subnet: continue if not subnet:
continue
nets.append((subnet, n.width())) nets.append((subnet, n.width()))
d = dict(host=s.host(), d = dict(host=s.host(),
nets=nets, nets=nets,

View File

@ -35,11 +35,14 @@ def _validate_width(v):
class SshuttleNet(NSObject): class SshuttleNet(NSObject):
def subnet(self): def subnet(self):
return getattr(self, '_k_subnet', None) return getattr(self, '_k_subnet', None)
def setSubnet_(self, v): def setSubnet_(self, v):
self._k_subnet = v self._k_subnet = v
config_changed() config_changed()
@objc_validator @objc_validator
def validateSubnet_error_(self, value, error): def validateSubnet_error_(self, value, error):
# print 'validateSubnet!' # print 'validateSubnet!'
@ -47,9 +50,11 @@ class SshuttleNet(NSObject):
def width(self): def width(self):
return getattr(self, '_k_width', 24) return getattr(self, '_k_width', 24)
def setWidth_(self, v): def setWidth_(self, v):
self._k_width = v self._k_width = v
config_changed() config_changed()
@objc_validator @objc_validator
def validateWidth_error_(self, value, error): def validateWidth_error_(self, value, error):
# print 'validateWidth!' # print 'validateWidth!'
@ -62,7 +67,9 @@ NET_MANUAL = 2
LAT_BANDWIDTH = 0 LAT_BANDWIDTH = 0
LAT_INTERACTIVE = 1 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()
config_changed() config_changed()
@ -70,22 +77,27 @@ class SshuttleServer(NSObject):
def wantConnect(self): def wantConnect(self):
return getattr(self, '_k_wantconnect', False) return getattr(self, '_k_wantconnect', False)
def setWantConnect_(self, v): def setWantConnect_(self, v):
self._k_wantconnect = v self._k_wantconnect = v
self.setError_(None) self.setError_(None)
config_changed() config_changed()
if setconnect_callback: setconnect_callback(self) if setconnect_callback:
setconnect_callback(self)
def connected(self): def connected(self):
return getattr(self, '_k_connected', False) return getattr(self, '_k_connected', False)
def setConnected_(self, v): def setConnected_(self, v):
print 'setConnected of %r to %r' % (self, v) print 'setConnected of %r to %r' % (self, v)
self._k_connected = v self._k_connected = v
if v: self.setError_(None) # connected ok, so no error if v:
self.setError_(None) # connected ok, so no error
config_changed() config_changed()
def error(self): def error(self):
return getattr(self, '_k_error', None) return getattr(self, '_k_error', None)
def setError_(self, v): def setError_(self, v):
self._k_error = v self._k_error = v
config_changed() config_changed()
@ -109,16 +121,19 @@ class SshuttleServer(NSObject):
n = self.nets() n = self.nets()
suffix = ' (%d subnet%s)' % (len(n), len(n) != 1 and 's' or '') suffix = ' (%d subnet%s)' % (len(n), len(n) != 1 and 's' or '')
return self.host() + suffix return self.host() + suffix
def setTitle_(self, v): def setTitle_(self, v):
# title is always auto-generated # title is always auto-generated
config_changed() 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) self.setTitle_(None)
config_changed() config_changed()
@objc_validator @objc_validator
def validateHost_error_(self, value, error): def validateHost_error_(self, value, error):
# print 'validatehost! %r %r %r' % (self, value, error) # print 'validatehost! %r %r %r' % (self, value, error)
@ -128,19 +143,23 @@ class SshuttleServer(NSObject):
def nets(self): def nets(self):
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) self.setTitle_(None)
config_changed() config_changed()
def netsHidden(self): def netsHidden(self):
# print 'checking netsHidden' # print 'checking netsHidden'
return self.autoNets() != NET_MANUAL return self.autoNets() != NET_MANUAL
def setNetsHidden_(self, v): def setNetsHidden_(self, v):
config_changed() config_changed()
# print 'setting netsHidden to %r' % v # print 'setting netsHidden to %r' % v
def autoNets(self): def autoNets(self):
return getattr(self, '_k_autoNets', NET_AUTO) return getattr(self, '_k_autoNets', NET_AUTO)
def setAutoNets_(self, v): def setAutoNets_(self, v):
self._k_autoNets = v self._k_autoNets = v
self.setNetsHidden_(-1) self.setNetsHidden_(-1)
@ -150,18 +169,21 @@ class SshuttleServer(NSObject):
def autoHosts(self): def autoHosts(self):
return getattr(self, '_k_autoHosts', True) return getattr(self, '_k_autoHosts', True)
def setAutoHosts_(self, v): def setAutoHosts_(self, v):
self._k_autoHosts = v self._k_autoHosts = v
config_changed() config_changed()
def useDns(self): def useDns(self):
return getattr(self, '_k_useDns', False) return getattr(self, '_k_useDns', False)
def setUseDns_(self, v): def setUseDns_(self, v):
self._k_useDns = v self._k_useDns = v
config_changed() config_changed()
def latencyControl(self): def latencyControl(self):
return getattr(self, '_k_latencyControl', LAT_INTERACTIVE) return getattr(self, '_k_latencyControl', LAT_INTERACTIVE)
def setLatencyControl_(self, v): def setLatencyControl_(self, v):
self._k_latencyControl = v self._k_latencyControl = v
config_changed() config_changed()

View File

@ -1,4 +1,4 @@
import sys, os import os
from AppKit import * from AppKit import *
import PyObjCTools.AppHelper import PyObjCTools.AppHelper
@ -44,11 +44,13 @@ def Defaults():
# #
def DelayedCallback(func, *args, **kwargs): def DelayedCallback(func, *args, **kwargs):
flag = [0] flag = [0]
def _go(): def _go():
if flag[0]: if flag[0]:
print 'running %r (flag=%r)' % (func, flag) print 'running %r (flag=%r)' % (func, flag)
flag[0] = 0 flag[0] = 0
func(*args, **kwargs) func(*args, **kwargs)
def call(): def call():
flag[0] += 1 flag[0] += 1
PyObjCTools.AppHelper.callAfter(_go) PyObjCTools.AppHelper.callAfter(_go)