Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
sshuttle
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
pub
sshuttle
Commits
f1c79c7e
Commit
f1c79c7e
authored
Sep 16, 2014
by
Brian May
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
PEP8 fixes.
parent
5529a04c
Changes
16
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
569 additions
and
377 deletions
+569
-377
assembler.py
src/assembler.py
+2
-1
client.py
src/client.py
+119
-82
firewall.py
src/firewall.py
+110
-74
helpers.py
src/helpers.py
+12
-7
hostwatch.py
src/hostwatch.py
+26
-20
main.py
src/main.py
+45
-39
options.py
src/options.py
+26
-13
server.py
src/server.py
+61
-40
ssh.py
src/ssh.py
+18
-13
ssnet.py
src/ssnet.py
+50
-37
ssyslog.py
src/ssyslog.py
+4
-1
stresstest.py
src/stresstest.py
+10
-7
askpass.py
src/ui-macos/askpass.py
+4
-2
main.py
src/ui-macos/main.py
+46
-29
models.py
src/ui-macos/models.py
+33
-11
my.py
src/ui-macos/my.py
+3
-1
No files found.
src/assembler.py
View file @
f1c79c7e
import
sys
,
zlib
import
sys
import
zlib
z
=
zlib
.
decompressobj
()
mainmod
=
sys
.
modules
[
__name__
]
...
...
src/client.py
View file @
f1c79c7e
This diff is collapsed.
Click to expand it.
src/firewall.py
View file @
f1c79c7e
This diff is collapsed.
Click to expand it.
src/helpers.py
View file @
f1c79c7e
import
sys
,
os
,
socket
,
errno
import
sys
import
socket
import
errno
logprefix
=
''
verbose
=
0
def
log
(
s
):
try
:
sys
.
stdout
.
flush
()
...
...
@@ -13,14 +16,17 @@ def log(s):
# our tty closes. That sucks, but it's no reason to abort the program.
pass
def
debug1
(
s
):
if
verbose
>=
1
:
log
(
s
)
def
debug2
(
s
):
if
verbose
>=
2
:
log
(
s
)
def
debug3
(
s
):
if
verbose
>=
3
:
log
(
s
)
...
...
@@ -43,9 +49,9 @@ def resolvconf_nameservers():
words
=
line
.
lower
()
.
split
()
if
len
(
words
)
>=
2
and
words
[
0
]
==
'nameserver'
:
if
':'
in
words
[
1
]:
l
.
append
((
socket
.
AF_INET6
,
words
[
1
]))
l
.
append
((
socket
.
AF_INET6
,
words
[
1
]))
else
:
l
.
append
((
socket
.
AF_INET
,
words
[
1
]))
l
.
append
((
socket
.
AF_INET
,
words
[
1
]))
return
l
...
...
@@ -58,10 +64,10 @@ def resolvconf_random_nameserver():
random
.
shuffle
(
l
)
return
l
[
0
]
else
:
return
(
socket
.
AF_INET
,
'127.0.0.1'
)
return
(
socket
.
AF_INET
,
'127.0.0.1'
)
def
islocal
(
ip
,
family
):
def
islocal
(
ip
,
family
):
sock
=
socket
.
socket
(
family
)
try
:
try
:
...
...
@@ -83,4 +89,3 @@ def family_to_string(family):
return
"AF_INET"
else
:
return
str
(
family
)
src/hostwatch.py
View file @
f1c79c7e
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'
):
import
compat.ssubprocess
as
ssubprocess
import
helpers
from
helpers
import
*
from
helpers
import
log
,
debug1
,
debug2
,
debug3
POLL_TIME
=
60
*
15
POLL_TIME
=
60
*
15
NETSTAT_POLL_TIME
=
30
CACHEFILE
=
os
.
path
.
expanduser
(
'~/.sshuttle.hosts'
)
CACHEFILE
=
os
.
path
.
expanduser
(
'~/.sshuttle.hosts'
)
_nmb_ok
=
True
...
...
@@ -28,7 +34,7 @@ def write_host_cache():
tmpname
=
'
%
s.
%
d.tmp'
%
(
CACHEFILE
,
os
.
getpid
())
try
:
f
=
open
(
tmpname
,
'wb'
)
for
name
,
ip
in
sorted
(
hostnames
.
items
()):
for
name
,
ip
in
sorted
(
hostnames
.
items
()):
f
.
write
(
'
%
s,
%
s
\n
'
%
(
name
,
ip
))
f
.
close
()
os
.
rename
(
tmpname
,
CACHEFILE
)
...
...
@@ -50,7 +56,7 @@ def read_host_cache():
for
line
in
f
:
words
=
line
.
strip
()
.
split
(
','
)
if
len
(
words
)
==
2
:
(
name
,
ip
)
=
words
(
name
,
ip
)
=
words
name
=
re
.
sub
(
r'[^-\w]'
,
'-'
,
name
)
.
strip
()
ip
=
re
.
sub
(
r'[^0-9.]'
,
''
,
ip
)
.
strip
()
if
name
and
ip
:
...
...
@@ -94,7 +100,7 @@ def _check_revdns(ip):
debug3
(
'<
%
s
\n
'
%
r
[
0
])
check_host
(
r
[
0
])
found_host
(
r
[
0
],
ip
)
except
socket
.
herror
,
e
:
except
socket
.
herror
:
pass
...
...
@@ -105,7 +111,7 @@ def _check_dns(hostname):
debug3
(
'<
%
s
\n
'
%
ip
)
check_host
(
ip
)
found_host
(
hostname
,
ip
)
except
socket
.
gaierror
,
e
:
except
socket
.
gaierror
:
pass
...
...
@@ -187,7 +193,7 @@ def _check_nmb(hostname, is_workgroup, is_master):
global
_nmb_ok
if
not
_nmb_ok
:
return
argv
=
[
'nmblookup'
]
+
[
'-M'
]
*
is_master
+
[
'--'
,
hostname
]
argv
=
[
'nmblookup'
]
+
[
'-M'
]
*
is_master
+
[
'--'
,
hostname
]
debug2
(
' > n
%
d
%
d:
%
s
\n
'
%
(
is_workgroup
,
is_master
,
hostname
))
try
:
p
=
ssubprocess
.
Popen
(
argv
,
stdout
=
ssubprocess
.
PIPE
,
stderr
=
null
)
...
...
@@ -228,13 +234,13 @@ def check_workgroup(hostname):
def
_enqueue
(
op
,
*
args
):
t
=
(
op
,
args
)
if
queue
.
get
(
t
)
==
None
:
t
=
(
op
,
args
)
if
queue
.
get
(
t
)
is
None
:
queue
[
t
]
=
0
def
_stdin_still_ok
(
timeout
):
r
,
w
,
x
=
select
.
select
([
sys
.
stdin
.
fileno
()],
[],
[],
timeout
)
r
,
w
,
x
=
select
.
select
([
sys
.
stdin
.
fileno
()],
[],
[],
timeout
)
if
r
:
b
=
os
.
read
(
sys
.
stdin
.
fileno
(),
4096
)
if
not
b
:
...
...
@@ -261,8 +267,8 @@ def hw_main(seed_hosts):
while
1
:
now
=
time
.
time
()
for
t
,
last_polled
in
queue
.
items
():
(
op
,
args
)
=
t
for
t
,
last_polled
in
queue
.
items
():
(
op
,
args
)
=
t
if
not
_stdin_still_ok
(
0
):
break
maxtime
=
POLL_TIME
...
...
src/main.py
View file @
f1c79c7e
import
sys
,
os
,
re
,
socket
import
helpers
,
options
,
client
,
server
,
firewall
,
hostwatch
import
compat.ssubprocess
as
ssubprocess
from
helpers
import
*
import
sys
import
re
import
socket
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
...
...
@@ -9,17 +15,17 @@ def parse_subnet4(s):
m
=
re
.
match
(
r'(\d+)(?:\.(\d+)\.(\d+)\.(\d+))?(?:/(\d+))?$'
,
s
)
if
not
m
:
raise
Fatal
(
'
%
r is not a valid IP subnet format'
%
s
)
(
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
))
if
width
==
None
:
(
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
))
if
width
is
None
:
width
=
32
else
:
width
=
int
(
width
)
if
a
>
255
or
b
>
255
or
c
>
255
or
d
>
255
:
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
width
>
32
:
raise
Fatal
(
'*/
%
d is greater than the maximum of 32'
%
width
)
return
(
socket
.
AF_INET
,
'
%
d.
%
d.
%
d.
%
d'
%
(
a
,
b
,
c
,
d
),
width
)
return
(
socket
.
AF_INET
,
'
%
d.
%
d.
%
d.
%
d'
%
(
a
,
b
,
c
,
d
),
width
)
# 1:2::3/64 or just 1:2::3
...
...
@@ -27,8 +33,8 @@ def parse_subnet6(s):
m
=
re
.
match
(
r'(?:([a-fA-F\d:]+))?(?:/(\d+))?$'
,
s
)
if
not
m
:
raise
Fatal
(
'
%
r is not a valid IP subnet format'
%
s
)
(
net
,
width
)
=
m
.
groups
()
if
width
==
None
:
(
net
,
width
)
=
m
.
groups
()
if
width
is
None
:
width
=
128
else
:
width
=
int
(
width
)
...
...
@@ -41,7 +47,7 @@ def parse_subnet6(s):
def
parse_subnet_file
(
s
):
try
:
handle
=
open
(
s
,
'r'
)
except
OSError
,
e
:
except
OSError
:
raise
Fatal
(
'Unable to open subnet file:
%
s'
%
s
)
raw_config_lines
=
handle
.
readlines
()
...
...
@@ -77,16 +83,16 @@ def parse_ipport4(s):
m
=
re
.
match
(
r'(?:(\d+)\.(\d+)\.(\d+)\.(\d+))?(?::)?(?:(\d+))?$'
,
s
)
if
not
m
:
raise
Fatal
(
'
%
r is not a valid IP:port format'
%
s
)
(
a
,
b
,
c
,
d
,
port
)
=
m
.
groups
()
(
a
,
b
,
c
,
d
,
port
)
=
(
int
(
a
or
0
),
int
(
b
or
0
),
int
(
c
or
0
),
int
(
d
or
0
),
(
a
,
b
,
c
,
d
,
port
)
=
m
.
groups
()
(
a
,
b
,
c
,
d
,
port
)
=
(
int
(
a
or
0
),
int
(
b
or
0
),
int
(
c
or
0
),
int
(
d
or
0
),
int
(
port
or
0
))
if
a
>
255
or
b
>
255
or
c
>
255
or
d
>
255
:
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
:
raise
Fatal
(
'*:
%
d is greater than the maximum of 65535'
%
port
)
if
a
==
None
:
if
a
is
None
:
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:2::3]:456 or [1:2::3] or 456
...
...
@@ -95,8 +101,8 @@ def parse_ipport6(s):
m
=
re
.
match
(
r'(?:\[([^]]*)])?(?::)?(?:(\d+))?$'
,
s
)
if
not
m
:
raise
Fatal
(
'
%
s is not a valid IP:port format'
%
s
)
(
ip
,
port
)
=
m
.
groups
()
(
ip
,
port
)
=
(
ip
or
'::'
,
int
(
port
or
0
))
(
ip
,
port
)
=
m
.
groups
()
(
ip
,
port
)
=
(
ip
or
'::'
,
int
(
port
or
0
))
return
(
ip
,
port
)
...
...
@@ -156,8 +162,8 @@ try:
o
.
fatal
(
'at least one subnet, subnet file, or -N expected'
)
includes
=
extra
excludes
=
[
'127.0.0.0/8'
]
for
k
,
v
in
flags
:
if
k
in
(
'-x'
,
'--exclude'
):
for
k
,
v
in
flags
:
if
k
in
(
'-x'
,
'--exclude'
):
excludes
.
append
(
v
)
remotename
=
opt
.
remote
if
remotename
==
''
or
remotename
==
'-'
:
...
...
@@ -174,10 +180,10 @@ try:
includes
=
parse_subnet_file
(
opt
.
subnets
)
if
not
opt
.
method
:
method
=
"auto"
elif
opt
.
method
in
[
"auto"
,
"nat"
,
"tproxy"
,
"ipfw"
]:
elif
opt
.
method
in
[
"auto"
,
"nat"
,
"tproxy"
,
"ipfw"
]:
method
=
opt
.
method
else
:
o
.
fatal
(
"method
%
s not supported"
%
opt
.
method
)
o
.
fatal
(
"method
%
s not supported"
%
opt
.
method
)
if
not
opt
.
listen
:
if
opt
.
method
==
"tproxy"
:
ipport_v6
=
parse_ipport6
(
'[::1]:0'
)
...
...
src/options.py
View file @
f1c79c7e
"""Command-line options parser.
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
:
def
__init__
(
self
):
self
.
_opts
=
{}
...
...
@@ -46,7 +53,8 @@ def _atoi(v):
def
_remove_negative_kv
(
k
,
v
):
if
k
.
startswith
(
'no-'
)
or
k
.
startswith
(
'no_'
):
return
k
[
3
:],
not
v
return
k
,
v
return
k
,
v
def
_remove_negative_k
(
k
):
return
_remove_negative_kv
(
k
,
None
)[
0
]
...
...
@@ -55,15 +63,17 @@ def _remove_negative_k(k):
def
_tty_width
():
s
=
struct
.
pack
(
"HHHH"
,
0
,
0
,
0
,
0
)
try
:
import
fcntl
,
termios
import
fcntl
import
termios
s
=
fcntl
.
ioctl
(
sys
.
stderr
.
fileno
(),
termios
.
TIOCGWINSZ
,
s
)
except
(
IOError
,
ImportError
):
return
_atoi
(
os
.
environ
.
get
(
'WIDTH'
))
or
70
(
ysize
,
xsize
,
ypix
,
xpix
)
=
struct
.
unpack
(
'HHHH'
,
s
)
(
ysize
,
xsize
,
ypix
,
xpix
)
=
struct
.
unpack
(
'HHHH'
,
s
)
return
xsize
or
70
class
Options
:
"""Option parser.
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
...
...
@@ -76,6 +86,7 @@ class Options:
By default, the parser function is getopt.gnu_getopt, and the abort
behaviour is to exit the program.
"""
def
__init__
(
self
,
optspec
,
optfunc
=
getopt
.
gnu_getopt
,
onabort
=
_default_onabort
):
self
.
optspec
=
optspec
...
...
@@ -95,7 +106,8 @@ class Options:
first_syn
=
True
while
lines
:
l
=
lines
.
pop
()
if
l
==
'--'
:
break
if
l
==
'--'
:
break
out
.
append
(
'
%
s:
%
s
\n
'
%
(
first_syn
and
'usage'
or
' or'
,
l
))
first_syn
=
False
out
.
append
(
'
\n
'
)
...
...
@@ -122,7 +134,7 @@ class Options:
flagl
=
flags
.
split
(
','
)
flagl_nice
=
[]
for
_f
in
flagl
:
f
,
dvi
=
_remove_negative_kv
(
_f
,
_intify
(
defval
))
f
,
dvi
=
_remove_negative_kv
(
_f
,
_intify
(
defval
))
self
.
_aliases
[
f
]
=
_remove_negative_k
(
flagl
[
0
])
self
.
_hasparms
[
f
]
=
has_parm
self
.
_defaults
[
f
]
=
dvi
...
...
@@ -141,7 +153,7 @@ class Options:
prefix
=
'
%-20
s '
%
flags_nice
argtext
=
'
\n
'
.
join
(
textwrap
.
wrap
(
extra
,
width
=
_tty_width
(),
initial_indent
=
prefix
,
subsequent_indent
=
' '
*
28
))
subsequent_indent
=
' '
*
28
))
out
.
append
(
argtext
+
'
\n
'
)
last_was_option
=
True
else
:
...
...
@@ -170,17 +182,18 @@ class Options:
and "extra" is a list of positional arguments.
"""
try
:
(
flags
,
extra
)
=
self
.
optfunc
(
args
,
self
.
_shortopts
,
self
.
_longopts
)
(
flags
,
extra
)
=
self
.
optfunc
(
args
,
self
.
_shortopts
,
self
.
_longopts
)
except
getopt
.
GetoptError
,
e
:
self
.
fatal
(
e
)
opt
=
OptDict
()
for
k
,
v
in
self
.
_defaults
.
iteritems
():
for
k
,
v
in
self
.
_defaults
.
iteritems
():
k
=
self
.
_aliases
[
k
]
opt
[
k
]
=
v
for
(
k
,
v
)
in
flags
:
for
(
k
,
v
)
in
flags
:
k
=
k
.
lstrip
(
'-'
)
if
k
in
(
'h'
,
'?'
,
'help'
):
self
.
usage
()
...
...
@@ -195,6 +208,6 @@ class Options:
else
:
v
=
_intify
(
v
)
opt
[
k
]
=
v
for
(
f1
,
f2
)
in
self
.
_aliases
.
iteritems
():
for
(
f1
,
f2
)
in
self
.
_aliases
.
iteritems
():
opt
[
f1
]
=
opt
.
_opts
.
get
(
f2
)
return
(
opt
,
flags
,
extra
)
return
(
opt
,
flags
,
extra
)
src/server.py
View file @
f1c79c7e
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'
):
import
ssnet
,
helpers
,
hostwatch
import
ssnet
import
helpers
import
hostwatch
import
compat.ssubprocess
as
ssubprocess
from
ssnet
import
SockWrapper
,
Handler
,
Proxy
,
Mux
,
MuxWrapper
from
helpers
import
*
from
ssnet
import
Handler
,
Proxy
,
Mux
,
MuxWrapper
from
helpers
import
log
,
debug1
,
debug2
,
debug3
,
Fatal
,
\
resolvconf_random_nameserver
if
not
globals
()
.
get
(
'latency_control'
):
latency_control
=
None
def
_ipmatch
(
ipstr
):
...
...
@@ -14,13 +27,13 @@ def _ipmatch(ipstr):
g
=
m
.
groups
()
ips
=
g
[
0
]
width
=
int
(
g
[
4
]
or
32
)
if
g
[
1
]
==
None
:
if
g
[
1
]
is
None
:
ips
+=
'.0.0.0'
width
=
min
(
width
,
8
)
elif
g
[
2
]
==
None
:
elif
g
[
2
]
is
None
:
ips
+=
'.0.0'
width
=
min
(
width
,
16
)
elif
g
[
3
]
==
None
:
elif
g
[
3
]
is
None
:
ips
+=
'.0'
width
=
min
(
width
,
24
)
return
(
struct
.
unpack
(
'!I'
,
socket
.
inet_aton
(
ips
))[
0
],
width
)
...
...
@@ -38,12 +51,12 @@ def _maskbits(netmask):
return
32
for
i
in
range
(
32
):
if
netmask
[
0
]
&
_shl
(
1
,
i
):
return
32
-
i
return
32
-
i
return
0
def
_shl
(
n
,
bits
):
return
n
*
int
(
2
**
bits
)
return
n
*
int
(
2
**
bits
)
def
_list_routes
():
...
...
@@ -58,8 +71,9 @@ def _list_routes():
maskw
=
_ipmatch
(
cols
[
2
])
# linux only
mask
=
_maskbits
(
maskw
)
# returns 32 if maskw is null
width
=
min
(
ipw
[
1
],
mask
)
ip
=
ipw
[
0
]
&
_shl
(
_shl
(
1
,
width
)
-
1
,
32
-
width
)
routes
.
append
((
socket
.
AF_INET
,
socket
.
inet_ntoa
(
struct
.
pack
(
'!I'
,
ip
)),
width
))
ip
=
ipw
[
0
]
&
_shl
(
_shl
(
1
,
width
)
-
1
,
32
-
width
)
routes
.
append
(
(
socket
.
AF_INET
,
socket
.
inet_ntoa
(
struct
.
pack
(
'!I'
,
ip
)),
width
))
rv
=
p
.
wait
()
if
rv
!=
0
:
log
(
'WARNING:
%
r returned
%
d
\n
'
%
(
argv
,
rv
))
...
...
@@ -68,9 +82,9 @@ def _list_routes():
def
list_routes
():
for
(
family
,
ip
,
width
)
in
_list_routes
():
for
(
family
,
ip
,
width
)
in
_list_routes
():
if
not
ip
.
startswith
(
'0.'
)
and
not
ip
.
startswith
(
'127.'
):
yield
(
family
,
ip
,
width
)
yield
(
family
,
ip
,
width
)
def
_exc_dump
():
...
...
@@ -79,7 +93,7 @@ def _exc_dump():
def
start_hostwatch
(
seed_hosts
):
s1
,
s2
=
socket
.
socketpair
()
s1
,
s2
=
socket
.
socketpair
()
pid
=
os
.
fork
()
if
not
pid
:
# child
...
...
@@ -91,27 +105,29 @@ def start_hostwatch(seed_hosts):
os
.
dup2
(
s1
.
fileno
(),
0
)
s1
.
close
()
rv
=
hostwatch
.
hw_main
(
seed_hosts
)
or
0
except
Exception
,
e
:
except
Exception
:
log
(
'
%
s
\n
'
%
_exc_dump
())
rv
=
98
finally
:
os
.
_exit
(
rv
)
s1
.
close
()
return
pid
,
s2
return
pid
,
s2
class
Hostwatch
:
def
__init__
(
self
):
self
.
pid
=
0
self
.
sock
=
None
class
DnsProxy
(
Handler
):
def
__init__
(
self
,
mux
,
chan
,
request
):
# FIXME! IPv4 specific
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_DGRAM
)
Handler
.
__init__
(
self
,
[
sock
])
self
.
timeout
=
time
.
time
()
+
30
self
.
timeout
=
time
.
time
()
+
30
self
.
mux
=
mux
self
.
chan
=
chan
self
.
tries
=
0
...
...
@@ -164,10 +180,11 @@ class DnsProxy(Handler):
class
UdpProxy
(
Handler
):
def
__init__
(
self
,
mux
,
chan
,
family
):
sock
=
socket
.
socket
(
family
,
socket
.
SOCK_DGRAM
)
Handler
.
__init__
(
self
,
[
sock
])
self
.
timeout
=
time
.
time
()
+
30
self
.
timeout
=
time
.
time
()
+
30
self
.
mux
=
mux
self
.
chan
=
chan
self
.
sock
=
sock
...
...
@@ -177,26 +194,28 @@ class UdpProxy(Handler):
def
send
(
self
,
dstip
,
data
):
debug2
(
'UDP: sending to
%
r port
%
d
\n
'
%
dstip
)
try
:
self
.
sock
.
sendto
(
data
,
dstip
)
self
.
sock
.
sendto
(
data
,
dstip
)
except
socket
.
error
,
e
:
log
(
'UDP send to
%
r port
%
d:
%
s
\n
'
%
(
dstip
[
0
],
dstip
[
1
],
e
))
return
def
callback
(
self
):
try
:
data
,
peer
=
self
.
sock
.
recvfrom
(
4096
)
data
,
peer
=
self
.
sock
.
recvfrom
(
4096
)
except
socket
.
error
,
e
:
log
(
'UDP recv from
%
r port
%
d:
%
s
\n
'
%
(
peer
[
0
],
peer
[
1
],
e
))
return
debug2
(
'UDP response:
%
d bytes
\n
'
%
len
(
data
))
hdr
=
"
%
s,
%
r,"
%
(
peer
[
0
],
peer
[
1
])
self
.
mux
.
send
(
self
.
chan
,
ssnet
.
CMD_UDP_DATA
,
hdr
+
data
)
hdr
=
"
%
s,
%
r,"
%
(
peer
[
0
],
peer
[
1
])
self
.
mux
.
send
(
self
.
chan
,
ssnet
.
CMD_UDP_DATA
,
hdr
+
data
)
def
main
():
if
helpers
.
verbose
>=
1
:
helpers
.
logprefix
=
' s: '
else
:
helpers
.
logprefix
=
'server: '
assert
latency_control
is
not
None
debug1
(
'latency control setting =
%
r
\n
'
%
latency_control
)
routes
=
list
(
list_routes
())
...
...
@@ -239,13 +258,13 @@ def main():
def
got_host_req
(
data
):
if
not
hw
.
pid
:
(
hw
.
pid
,
hw
.
sock
)
=
start_hostwatch
(
data
.
strip
()
.
split
())
handlers
.
append
(
Handler
(
socks
=
[
hw
.
sock
],
callback
=
hostwatch_ready
))
(
hw
.
pid
,
hw
.
sock
)
=
start_hostwatch
(
data
.
strip
()
.
split
())
handlers
.
append
(
Handler
(
socks
=
[
hw
.
sock
],
callback
=
hostwatch_ready
))
mux
.
got_host_req
=
got_host_req
def
new_channel
(
channel
,
data
):
(
family
,
dstip
,
dstport
)
=
data
.
split
(
','
,
2
)
(
family
,
dstip
,
dstport
)
=
data
.
split
(
','
,
2
)
family
=
int
(
family
)
dstport
=
int
(
dstport
)
outwrap
=
ssnet
.
connect_dst
(
family
,
dstip
,
dstport
)
...
...
@@ -253,6 +272,7 @@ def main():
mux
.
new_channel
=
new_channel
dnshandlers
=
{}
def
dns_req
(
channel
,
data
):
debug2
(
'Incoming DNS request channel=
%
d.
\n
'
%
channel
)
h
=
DnsProxy
(
mux
,
channel
,
data
)
...
...
@@ -261,14 +281,15 @@ def main():
mux
.
got_dns_req
=
dns_req
udphandlers
=
{}
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
:
(
dstip
,
dstport
,
data
)
=
data
.
split
(
","
,
2
)
(
dstip
,
dstport
,
data
)
=
data
.
split
(
","
,
2
)
dstport
=
int
(
dstport
)
debug2
(
'is incoming UDP data.
%
r
%
d.
\n
'
%
(
dstip
,
dstport
))
debug2
(
'is incoming UDP data.
%
r
%
d.
\n
'
%
(
dstip
,
dstport
))
h
=
udphandlers
[
channel
]
h
.
send
((
dstip
,
dstport
),
data
)
h
.
send
((
dstip
,
dstport
),
data
)
elif
cmd
==
ssnet
.
CMD_UDP_CLOSE
:
debug2
(
'is incoming UDP close
\n
'
)
h
=
udphandlers
[
channel
]
...
...
@@ -280,20 +301,20 @@ def main():
family
=
int
(
data
)
mux
.
channels
[
channel
]
=
lambda
cmd
,
data
:
udp_req
(
channel
,
cmd
,
data
)
if
channel
in
udphandlers
:
raise
Fatal
(
'UDP connection channel
%
d already open'
%
channel
)
raise
Fatal
(
'UDP connection channel
%
d already open'
%
channel
)
else
:
h
=
UdpProxy
(
mux
,
channel
,
family
)
handlers
.
append
(
h
)
udphandlers
[
channel
]
=
h
mux
.
got_udp_open
=
udp_open
while
mux
.
ok
:
if
hw
.
pid
:
assert
(
hw
.
pid
>
0
)
(
rpid
,
rv
)
=
os
.
waitpid
(
hw
.
pid
,
os
.
WNOHANG
)
if
rpid
:
raise
Fatal
(
'hostwatch exited unexpectedly: code 0x
%04
x
\n
'
%
rv
)
raise
Fatal
(
'hostwatch exited unexpectedly: code 0x
%04
x
\n
'
%
rv
)
ssnet
.
runonce
(
handlers
,
mux
)
if
latency_control
:
...
...
@@ -302,12 +323,12 @@ def main():
if
dnshandlers
:
now
=
time
.
time
()
for
channel
,
h
in
dnshandlers
.
items
():
for
channel
,
h
in
dnshandlers
.
items
():
if
h
.
timeout
<
now
or
not
h
.
ok
:
debug3
(
'expiring dnsreqs channel=
%
d
\n
'
%
channel
)
del
dnshandlers
[
channel
]
h
.
ok
=
False
for
channel
,
h
in
udphandlers
.
items
():
for
channel
,
h
in
udphandlers
.
items
():
if
not
h
.
ok
:
debug3
(
'expiring UDP channel=
%
d
\n
'
%
channel
)
del
udphandlers
[
channel
]
...
...
src/ssh.py
View file @
f1c79c7e
import
sys
,
os
,
re
,
socket
,
zlib
import
sys
import
os
import
re
import
socket
import
zlib
import
compat.ssubprocess
as
ssubprocess
import
helpers
from
helpers
import
*
from
helpers
import
debug2
def
readfile
(
name
):
...
...
@@ -15,7 +19,7 @@ def readfile(name):
def
empackage
(
z
,
filename
,
data
=
None
):
(
path
,
basename
)
=
os
.
path
.
split
(
filename
)
(
path
,
basename
)
=
os
.
path
.
split
(
filename
)
if
not
data
:
data
=
readfile
(
filename
)
content
=
z
.
compress
(
data
)
...
...
@@ -24,7 +28,6 @@ def empackage(z, filename, data=None):
def
connect
(
ssh_cmd
,
rhostport
,
python
,
stderr
,
options
):
main_exe
=
sys
.
argv
[
0
]
portl
=
[]
if
(
rhostport
or
''
)
.
count
(
':'
)
>
1
:
...
...
@@ -35,7 +38,9 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
result
[
1
]
=
result
[
1
]
.
strip
(
':'
)
if
result
[
1
]
is
not
''
:
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
else
:
# IPv4
l
=
(
rhostport
or
''
)
.
split
(
':'
,
1
)
...
...
@@ -48,7 +53,7 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
z
=
zlib
.
compressobj
(
1
)
content
=
readfile
(
'assembler.py'
)
optdata
=
''
.
join
(
"
%
s=
%
r
\n
"
%
(
k
,
v
)
for
(
k
,
v
)
in
options
.
items
())
optdata
=
''
.
join
(
"
%
s=
%
r
\n
"
%
(
k
,
v
)
for
(
k
,
v
)
in
options
.
items
())
content2
=
(
empackage
(
z
,
'cmdline_options.py'
,
optdata
)
+
empackage
(
z
,
'helpers.py'
)
+
empackage
(
z
,
'compat/ssubprocess.py'
)
+
...
...
@@ -65,7 +70,6 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
"""
%
(
helpers
.
verbose
or
0
,
len
(
content
))
pyscript
=
re
.
sub
(
r'\s+'
,
' '
,
pyscript
.
strip
())
if
not
rhost
:
# ignore the --python argument when running locally; we already know
# which python version works.
...
...
@@ -83,11 +87,12 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
argv
=
(
sshl
+
portl
+
[
rhost
,
'--'
,
pycmd
])
(
s1
,
s2
)
=
socket
.
socketpair
()
(
s1
,
s2
)
=
socket
.
socketpair
()
def
setup
():
# runs in the child process
s2
.
close
()
s1a
,
s1b
=
os
.
dup
(
s1
.
fileno
()),
os
.
dup
(
s1
.
fileno
())
s1a
,
s1b
=
os
.
dup
(
s1
.
fileno
()),
os
.
dup
(
s1
.
fileno
())
s1
.
close
()
debug2
(
'executing:
%
r
\n
'
%
argv
)
p
=
ssubprocess
.
Popen
(
argv
,
stdin
=
s1a
,
stdout
=
s1b
,
preexec_fn
=
setup
,
...
...
src/ssnet.py
View file @
f1c79c7e
import
struct
,
socket
,
errno
,
select
import
struct
import
socket
import
errno
import
select
import
os
if
not
globals
()
.
get
(
'skip_imports'
):
from
helpers
import
*
from
helpers
import
log
,
debug1
,
debug2
,
debug3
,
Fatal
MAX_CHANNEL
=
65535
...
...
@@ -92,7 +96,10 @@ def _try_peername(sock):
_swcount
=
0
class
SockWrapper
:
def
__init__
(
self
,
rsock
,
wsock
,
connect_to
=
None
,
peername
=
None
):
global
_swcount
_swcount
+=
1
...
...
@@ -177,7 +184,7 @@ class SockWrapper:
if
not
self
.
shut_read
:
debug2
(
'
%
r: done reading
\n
'
%
self
)
self
.
shut_read
=
True
#self.rsock.shutdown(SHUT_RD) # doesn't do anything anyway
#
self.rsock.shutdown(SHUT_RD) # doesn't do anything anyway
def
nowrite
(
self
):
if
not
self
.
shut_write
:
...
...
@@ -243,7 +250,8 @@ class SockWrapper:
class
Handler
:
def
__init__
(
self
,
socks
=
None
,
callback
=
None
):
def
__init__
(
self
,
socks
=
None
,
callback
=
None
):
self
.
ok
=
True
self
.
socks
=
socks
or
[]
if
callback
:
...
...
@@ -255,7 +263,7 @@ class Handler:
def
callback
(
self
):
log
(
'--no callback defined--
%
r
\n
'
%
self
)
(
r
,
w
,
x
)
=
select
.
select
(
self
.
socks
,
[],
[],
0
)
(
r
,
w
,
x
)
=
select
.
select
(
self
.
socks
,
[],
[],
0
)
for
s
in
r
:
v
=
s
.
recv
(
4096
)
if
not
v
:
...
...
@@ -265,6 +273,7 @@ class Handler:
class
Proxy
(
Handler
):
def
__init__
(
self
,
wrap1
,
wrap2
):
Handler
.
__init__
(
self
,
[
wrap1
.
rsock
,
wrap1
.
wsock
,
wrap2
.
rsock
,
wrap2
.
wsock
])
...
...
@@ -272,8 +281,10 @@ class Proxy(Handler):
self
.
wrap2
=
wrap2
def
pre_select
(
self
,
r
,
w
,
x
):
if
self
.
wrap1
.
shut_write
:
self
.
wrap2
.
noread
()
if
self
.
wrap2
.
shut_write
:
self
.
wrap1
.
noread
()
if
self
.
wrap1
.
shut_write
:
self
.
wrap2
.
noread
()
if
self
.
wrap2
.
shut_write
:
self
.
wrap1
.
noread
()
if
self
.
wrap1
.
connect_to
:
_add
(
w
,
self
.
wrap1
.
rsock
)
...
...
@@ -312,6 +323,7 @@ class Proxy(Handler):
class
Mux
(
Handler
):
def
__init__
(
self
,
rsock
,
wsock
):
Handler
.
__init__
(
self
,
[
rsock
,
wsock
])
self
.
rsock
=
rsock
...
...
@@ -349,7 +361,7 @@ class Mux(Handler):
self
.
send
(
0
,
CMD_PING
,
'rttest'
)
self
.
too_full
=
True
#ob = []
#for b in self.outbuf:
#
for b in self.outbuf:
# (s1,s2,c) = struct.unpack('!ccH', b[:4])
# ob.append(c)
#log('outbuf: %d %r\n' % (self.amount_queued(), ob))
...
...
@@ -360,13 +372,13 @@ class Mux(Handler):
p
=
struct
.
pack
(
'!ccHHH'
,
'S'
,
'S'
,
channel
,
cmd
,
len
(
data
))
+
data
self
.
outbuf
.
append
(
p
)
debug2
(
' > channel=
%
d cmd=
%
s len=
%
d (fullness=
%
d)
\n
'
%
(
channel
,
cmd_to_name
.
get
(
cmd
,
hex
(
cmd
)),
%
(
channel
,
cmd_to_name
.
get
(
cmd
,
hex
(
cmd
)),
len
(
data
),
self
.
fullness
))
self
.
fullness
+=
len
(
data
)
def
got_packet
(
self
,
channel
,
cmd
,
data
):
debug2
(
'< channel=
%
d cmd=
%
s len=
%
d
\n
'
%
(
channel
,
cmd_to_name
.
get
(
cmd
,
hex
(
cmd
)),
len
(
data
)))
%
(
channel
,
cmd_to_name
.
get
(
cmd
,
hex
(
cmd
)),
len
(
data
)))
if
cmd
==
CMD_PING
:
self
.
send
(
0
,
CMD_PONG
,
data
)
elif
cmd
==
CMD_PONG
:
...
...
@@ -406,7 +418,7 @@ class Mux(Handler):
callback
=
self
.
channels
.
get
(
channel
)
if
not
callback
:
log
(
'warning: closed channel
%
d got cmd=
%
s len=
%
d
\n
'
%
(
channel
,
cmd_to_name
.
get
(
cmd
,
hex
(
cmd
)),
len
(
data
)))
%
(
channel
,
cmd_to_name
.
get
(
cmd
,
hex
(
cmd
)),
len
(
data
)))
else
:
callback
(
cmd
,
data
)
...
...
@@ -434,11 +446,11 @@ class Mux(Handler):
def
handle
(
self
):
self
.
fill
()
#log('inbuf is: (%d,%d) %r\n'
#
log('inbuf is: (%d,%d) %r\n'
# % (self.want, len(self.inbuf), self.inbuf))
while
1
:
if
len
(
self
.
inbuf
)
>=
(
self
.
want
or
HDR_LEN
):
(
s1
,
s2
,
channel
,
cmd
,
datalen
)
=
\
(
s1
,
s2
,
channel
,
cmd
,
datalen
)
=
\
struct
.
unpack
(
'!ccHHH'
,
self
.
inbuf
[:
HDR_LEN
])
assert
(
s1
==
'S'
)
assert
(
s2
==
'S'
)
...
...
@@ -457,7 +469,7 @@ class Mux(Handler):
_add
(
w
,
self
.
wsock
)
def
callback
(
self
):
(
r
,
w
,
x
)
=
select
.
select
([
self
.
rsock
],
[
self
.
wsock
],
[],
0
)
(
r
,
w
,
x
)
=
select
.
select
([
self
.
rsock
],
[
self
.
wsock
],
[],
0
)
if
self
.
rsock
in
r
:
self
.
handle
()
if
self
.
outbuf
and
self
.
wsock
in
w
:
...
...
@@ -465,6 +477,7 @@ class Mux(Handler):
class
MuxWrapper
(
SockWrapper
):
def
__init__
(
self
,
mux
,
channel
):
SockWrapper
.
__init__
(
self
,
mux
.
rsock
,
mux
.
wsock
)
self
.
mux
=
mux
...
...
@@ -478,7 +491,7 @@ class MuxWrapper(SockWrapper):
SockWrapper
.
__del__
(
self
)
def
__repr__
(
self
):
return
'SW
%
r:Mux#
%
d'
%
(
self
.
peername
,
self
.
channel
)
return
'SW
%
r:Mux#
%
d'
%
(
self
.
peername
,
self
.
channel
)
def
noread
(
self
):
if
not
self
.
shut_read
:
...
...
@@ -532,8 +545,8 @@ def connect_dst(family, ip, port):
outsock
=
socket
.
socket
(
family
)
outsock
.
setsockopt
(
socket
.
SOL_IP
,
socket
.
IP_TTL
,
42
)
return
SockWrapper
(
outsock
,
outsock
,
connect_to
=
(
ip
,
port
),
peername
=
'
%
s:
%
d'
%
(
ip
,
port
))
connect_to
=
(
ip
,
port
),
peername
=
'
%
s:
%
d'
%
(
ip
,
port
))
def
runonce
(
handlers
,
mux
):
...
...
@@ -545,14 +558,14 @@ def runonce(handlers, mux):
handlers
.
remove
(
h
)
for
s
in
handlers
:
s
.
pre_select
(
r
,
w
,
x
)
s
.
pre_select
(
r
,
w
,
x
)
debug2
(
'Waiting:
%
d r=
%
r w=
%
r x=
%
r (fullness=
%
d/
%
d)
\n
'
%
(
len
(
handlers
),
_fds
(
r
),
_fds
(
w
),
_fds
(
x
),
mux
.
fullness
,
mux
.
too_full
))
(
r
,
w
,
x
)
=
select
.
select
(
r
,
w
,
x
)
(
r
,
w
,
x
)
=
select
.
select
(
r
,
w
,
x
)
debug2
(
' Ready:
%
d r=
%
r w=
%
r x=
%
r
\n
'
%
(
len
(
handlers
),
_fds
(
r
),
_fds
(
w
),
_fds
(
x
)))
ready
=
r
+
w
+
x
ready
=
r
+
w
+
x
did
=
{}
for
h
in
handlers
:
for
s
in
h
.
socks
:
...
...
src/ssyslog.py
View file @
f1c79c7e
import
sys
,
os
import
sys
import
os
from
compat
import
ssubprocess
_p
=
None
def
start_syslog
():
global
_p
_p
=
ssubprocess
.
Popen
([
'logger'
,
...
...
src/stresstest.py
View file @
f1c79c7e
#!/usr/bin/env python
import
sys
,
os
,
socket
,
select
,
struct
,
time
import
socket
import
select
import
struct
import
time
listener
=
socket
.
socket
()
listener
.
bind
((
'127.0.0.1'
,
0
))
...
...
@@ -23,7 +26,7 @@ while 1:
if
count
>=
16384
:
count
=
1
print
'cli CREATING
%
d'
%
count
b
=
struct
.
pack
(
'I'
,
count
)
+
'x'
*
count
b
=
struct
.
pack
(
'I'
,
count
)
+
'x'
*
count
remain
[
c
]
=
count
print
'cli >>
%
r'
%
len
(
b
)
c
.
send
(
b
)
...
...
@@ -32,13 +35,13 @@ while 1:
r
=
[
listener
]
time
.
sleep
(
0.1
)
else
:
r
=
[
listener
]
+
servers
+
clients
r
=
[
listener
]
+
servers
+
clients
print
'select(
%
d)'
%
len
(
r
)
r
,
w
,
x
=
select
.
select
(
r
,
[],
[],
5
)
r
,
w
,
x
=
select
.
select
(
r
,
[],
[],
5
)
assert
(
r
)
for
i
in
r
:
if
i
==
listener
:
s
,
addr
=
listener
.
accept
()
s
,
addr
=
listener
.
accept
()
servers
.
append
(
s
)
elif
i
in
servers
:
b
=
i
.
recv
(
4096
)
...
...
@@ -47,7 +50,7 @@ while 1:
assert
(
len
(
b
)
>=
4
)
want
=
struct
.
unpack
(
'I'
,
b
[:
4
])[
0
]
b
=
b
[
4
:]
#i.send('y'*want)
#
i.send('y'*want)
else
:
want
=
remain
[
i
]
if
want
<
len
(
b
):
...
...
@@ -64,7 +67,7 @@ while 1:
del
remain
[
i
]
else
:
print
'srv >>
%
r'
%
len
(
b
)
i
.
send
(
'y'
*
len
(
b
))
i
.
send
(
'y'
*
len
(
b
))
if
not
want
:
i
.
shutdown
(
socket
.
SHUT_WR
)
elif
i
in
clients
:
...
...
src/ui-macos/askpass.py
View file @
f1c79c7e
import
sys
,
os
,
re
,
subprocess
import
re
import
subprocess
def
askpass
(
prompt
):
prompt
=
prompt
.
replace
(
'"'
,
"'"
)
...
...
@@ -6,7 +8,7 @@ def askpass(prompt):
if
'yes/no'
in
prompt
:
return
"yes"
script
=
"""
script
=
"""
tell application "Finder"
activate
display dialog "
%
s"
\
...
...
src/ui-macos/main.py
View file @
f1c79c7e
import
sys
,
os
,
pty
import
sys
import
os
import
pty
from
AppKit
import
*
import
my
,
models
,
askpass
import
my
import
models
import
askpass
def
sshuttle_args
(
host
,
auto_nets
,
auto_hosts
,
dns
,
nets
,
debug
,
no_latency_control
):
...
...
@@ -21,21 +26,25 @@ def sshuttle_args(host, auto_nets, auto_hosts, dns, nets, debug,
class
_Callback
(
NSObject
):
def
initWithFunc_
(
self
,
func
):
self
=
super
(
_Callback
,
self
)
.
init
()
self
.
func
=
func
return
self
def
func_
(
self
,
obj
):
return
self
.
func
(
obj
)
class
Callback
:
def
__init__
(
self
,
func
):
self
.
obj
=
_Callback
.
alloc
()
.
initWithFunc_
(
func
)
self
.
sel
=
self
.
obj
.
func_
class
Runner
:
def
__init__
(
self
,
argv
,
logfunc
,
promptfunc
,
serverobj
):
print
'in __init__'
self
.
id
=
argv
...
...
@@ -49,7 +58,7 @@ class Runner:
self
.
logfunc
(
'
\n
Connecting to
%
s.
\n
'
%
self
.
serverobj
.
host
())
print
'will run:
%
r'
%
argv
self
.
serverobj
.
setConnected_
(
False
)
pid
,
fd
=
pty
.
fork
()
pid
,
fd
=
pty
.
fork
()
if
pid
==
0
:
# child
try
:
...
...
@@ -65,7 +74,8 @@ class Runner:
.
initWithFileDescriptor_closeOnDealloc_
(
fd
,
True
)
self
.
cb
=
Callback
(
self
.
gotdata
)
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
)
self
.
file
.
waitForDataInBackgroundAndNotify
()
...
...
@@ -73,8 +83,8 @@ class Runner:
self
.
wait
()
def
_try_wait
(
self
,
options
):
if
self
.
rv
==
None
and
self
.
pid
>
0
:
pid
,
code
=
os
.
waitpid
(
self
.
pid
,
options
)
if
self
.
rv
is
None
and
self
.
pid
>
0
:
pid
,
code
=
os
.
waitpid
(
self
.
pid
,
options
)
if
pid
==
self
.
pid
:
if
os
.
WIFEXITED
(
code
):
self
.
rv
=
os
.
WEXITSTATUS
(
code
)
...
...
@@ -95,7 +105,7 @@ class Runner:
def
kill
(
self
):
assert
(
self
.
pid
>
0
)
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
())
os
.
kill
(
self
.
pid
,
15
)
self
.
wait
()
...
...
@@ -118,10 +128,11 @@ class Runner:
self
.
file
.
writeData_
(
my
.
Data
(
resp
+
'
\n
'
))
self
.
file
.
waitForDataInBackgroundAndNotify
()
self
.
poll
()
#print 'gotdata done!'
#
print 'gotdata done!'
class
SshuttleApp
(
NSObject
):
def
initialize
(
self
):
d
=
my
.
PList
(
'UserDefaults'
)
my
.
Defaults
()
.
registerDefaults_
(
d
)
...
...
@@ -145,12 +156,14 @@ class SshuttleController(NSObject):
host
=
server
.
host
()
print
'connecting
%
r'
%
host
self
.
fill_menu
()
def
logfunc
(
msg
):
print
'log! (
%
d bytes)'
%
len
(
msg
)
self
.
logField
.
textStorage
()
\
.
appendAttributedString_
(
NSAttributedString
.
alloc
()
\
.
appendAttributedString_
(
NSAttributedString
.
alloc
()
.
initWithString_
(
msg
))
self
.
logField
.
didChangeText
()
def
promptfunc
(
prompt
):
print
'prompt!
%
r'
%
prompt
return
askpass
.
askpass
(
prompt
)
...
...
@@ -164,12 +177,12 @@ class SshuttleController(NSObject):
manual_nets
=
[]
noLatencyControl
=
(
server
.
latencyControl
()
!=
models
.
LAT_INTERACTIVE
)
conn
=
Runner
(
sshuttle_args
(
host
,
auto_nets
=
nets_mode
==
models
.
NET_AUTO
,
auto_hosts
=
server
.
autoHosts
(),
dns
=
server
.
useDns
(),
nets
=
manual_nets
,
debug
=
self
.
debugField
.
state
(),
no_latency_control
=
noLatencyControl
),
auto_nets
=
nets_mode
==
models
.
NET_AUTO
,
auto_hosts
=
server
.
autoHosts
(),
dns
=
server
.
useDns
(),
nets
=
manual_nets
,
debug
=
self
.
debugField
.
state
(),
no_latency_control
=
noLatencyControl
),
logfunc
=
logfunc
,
promptfunc
=
promptfunc
,
serverobj
=
server
)
self
.
conns
[
host
]
=
conn
...
...
@@ -213,6 +226,7 @@ class SshuttleController(NSObject):
it
.
setRepresentedObject_
(
obj
)
it
.
setTarget_
(
self
)
it
.
setAction_
(
func
)
def
addnote
(
name
):
additem
(
name
,
None
,
None
)
...
...
@@ -271,7 +285,8 @@ class SshuttleController(NSObject):
sl
=
[]
for
s
in
l
:
host
=
s
.
get
(
'host'
,
None
)
if
not
host
:
continue
if
not
host
:
continue
nets
=
s
.
get
(
'nets'
,
[])
nl
=
[]
...
...
@@ -302,11 +317,13 @@ class SshuttleController(NSObject):
l
=
[]
for
s
in
self
.
servers
:
host
=
s
.
host
()
if
not
host
:
continue
if
not
host
:
continue
nets
=
[]
for
n
in
s
.
nets
():
subnet
=
n
.
subnet
()
if
not
subnet
:
continue
if
not
subnet
:
continue
nets
.
append
((
subnet
,
n
.
width
()))
d
=
dict
(
host
=
s
.
host
(),
nets
=
nets
,
...
...
src/ui-macos/models.py
View file @
f1c79c7e
...
...
@@ -35,24 +35,29 @@ def _validate_width(v):
class
SshuttleNet
(
NSObject
):
def
subnet
(
self
):
return
getattr
(
self
,
'_k_subnet'
,
None
)
def
setSubnet_
(
self
,
v
):
self
.
_k_subnet
=
v
config_changed
()
@
objc_validator
def
validateSubnet_error_
(
self
,
value
,
error
):
#print 'validateSubnet!'
#
print 'validateSubnet!'
return
True
,
_validate_ip
(
value
),
error
def
width
(
self
):
return
getattr
(
self
,
'_k_width'
,
24
)
def
setWidth_
(
self
,
v
):
self
.
_k_width
=
v
config_changed
()
@
objc_validator
def
validateWidth_error_
(
self
,
value
,
error
):
#print 'validateWidth!'
#
print 'validateWidth!'
return
True
,
_validate_width
(
value
),
error
NET_ALL
=
0
...
...
@@ -62,7 +67,9 @@ NET_MANUAL = 2
LAT_BANDWIDTH
=
0
LAT_INTERACTIVE
=
1
class
SshuttleServer
(
NSObject
):
def
init
(
self
):
self
=
super
(
SshuttleServer
,
self
)
.
init
()
config_changed
()
...
...
@@ -70,22 +77,27 @@ class SshuttleServer(NSObject):
def
wantConnect
(
self
):
return
getattr
(
self
,
'_k_wantconnect'
,
False
)
def
setWantConnect_
(
self
,
v
):
self
.
_k_wantconnect
=
v
self
.
setError_
(
None
)
config_changed
()
if
setconnect_callback
:
setconnect_callback
(
self
)
if
setconnect_callback
:
setconnect_callback
(
self
)
def
connected
(
self
):
return
getattr
(
self
,
'_k_connected'
,
False
)
def
setConnected_
(
self
,
v
):
print
'setConnected of
%
r to
%
r'
%
(
self
,
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
()
def
error
(
self
):
return
getattr
(
self
,
'_k_error'
,
None
)
def
setError_
(
self
,
v
):
self
.
_k_error
=
v
config_changed
()
...
...
@@ -107,40 +119,47 @@ class SshuttleServer(NSObject):
suffix
=
" (all traffic)"
elif
an
==
NET_MANUAL
:
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
def
setTitle_
(
self
,
v
):
# title is always auto-generated
config_changed
()
def
host
(
self
):
return
getattr
(
self
,
'_k_host'
,
None
)
def
setHost_
(
self
,
v
):
self
.
_k_host
=
v
self
.
setTitle_
(
None
)
config_changed
()
@
objc_validator
def
validateHost_error_
(
self
,
value
,
error
):
#print 'validatehost! %r %r %r' % (self, value, error)
#
print 'validatehost! %r %r %r' % (self, value, error)
while
value
.
startswith
(
'-'
):
value
=
value
[
1
:]
return
True
,
value
,
error
def
nets
(
self
):
return
getattr
(
self
,
'_k_nets'
,
[])
def
setNets_
(
self
,
v
):
self
.
_k_nets
=
v
self
.
setTitle_
(
None
)
config_changed
()
def
netsHidden
(
self
):
#print 'checking netsHidden'
#
print 'checking netsHidden'
return
self
.
autoNets
()
!=
NET_MANUAL
def
setNetsHidden_
(
self
,
v
):
config_changed
()
#print 'setting netsHidden to %r' % v
#
print 'setting netsHidden to %r' % v
def
autoNets
(
self
):
return
getattr
(
self
,
'_k_autoNets'
,
NET_AUTO
)
def
setAutoNets_
(
self
,
v
):
self
.
_k_autoNets
=
v
self
.
setNetsHidden_
(
-
1
)
...
...
@@ -150,18 +169,21 @@ class SshuttleServer(NSObject):
def
autoHosts
(
self
):
return
getattr
(
self
,
'_k_autoHosts'
,
True
)
def
setAutoHosts_
(
self
,
v
):
self
.
_k_autoHosts
=
v
config_changed
()
def
useDns
(
self
):
return
getattr
(
self
,
'_k_useDns'
,
False
)
def
setUseDns_
(
self
,
v
):
self
.
_k_useDns
=
v
config_changed
()
def
latencyControl
(
self
):
return
getattr
(
self
,
'_k_latencyControl'
,
LAT_INTERACTIVE
)
def
setLatencyControl_
(
self
,
v
):
self
.
_k_latencyControl
=
v
config_changed
()
src/ui-macos/my.py
View file @
f1c79c7e
import
sys
,
os
import
os
from
AppKit
import
*
import
PyObjCTools.AppHelper
...
...
@@ -44,11 +44,13 @@ def Defaults():
#
def
DelayedCallback
(
func
,
*
args
,
**
kwargs
):
flag
=
[
0
]
def
_go
():
if
flag
[
0
]:
print
'running
%
r (flag=
%
r)'
%
(
func
,
flag
)
flag
[
0
]
=
0
func
(
*
args
,
**
kwargs
)
def
call
():
flag
[
0
]
+=
1
PyObjCTools
.
AppHelper
.
callAfter
(
_go
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment