mirror of
https://github.com/sshuttle/sshuttle.git
synced 2025-05-05 16:44:40 +02:00
PEP8 fixes.
This commit is contained in:
parent
5529a04cc9
commit
f1c79c7e92
@ -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__]
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
22
src/main.py
22
src/main.py
@ -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)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
15
src/ssh.py
15
src/ssh.py
@ -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()
|
||||||
|
21
src/ssnet.py
21
src/ssnet.py
@ -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
|
||||||
|
@ -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',
|
||||||
|
@ -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))
|
||||||
|
@ -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('"', "'")
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user