Compare commits

...

9 Commits

Author SHA1 Message Date
57e744dadd ./do: use the latest minimal/do from the redo project. 2011-05-03 14:19:45 -07:00
c13be0b817 ui-macos/bits/runpython.do: auto-determine arches to build for.
Some people don't have all of them installed, so auto-detect them by
looking at the available arches in /usr/libexec.
2011-05-03 14:18:37 -07:00
da2c6273f6 Add some friendly info to the README 2011-05-03 14:03:19 -07:00
7712c60c36 Insert two binary NUL bytes (\0) before SSHUTTLE0001 sync string.
...and search for those null bytes before looking for the sync string.

This helps when people have misconfigured .bashrc to print messages even in
non-interactive mode.  (On my Debian Lenny system, .bashrc doesn't seem to
run when you do 'ssh localhost ls', but on MacOS servers, it does.  Hmm...)
2011-05-03 13:59:25 -07:00
65b0390fe9 ssh.py: use 'exec python -c' instead of just 'python -c'.
This gets rid of an extra intermediate sh process on the server that we were
keeping for no good reason, since it would exit as soon as python exited
anyway.
2011-05-03 13:51:09 -07:00
c5834a9773 Handle EHOSTDOWN, ENETDOWN.
Someone on the mailing list reported getting these.

Also centralize the list of these errors, so we don't have different parts
of the code supporting a different subset of them.  Now just use
ssnet.NET_ERRS.
2011-05-03 13:32:25 -07:00
e2474543fc runpython.do: also compile for ppc architecture. 2011-04-24 22:51:27 -04:00
8636378870 Dereference symlink for sshuttle launch script
(Modified slightly by apenwarr)
2011-04-24 22:42:50 -04:00
f5eed4c809 Don't try to connect to remote IPs that start with zero.
For some reason, on Linux servers this returns EINVAL.  I don't like just
treating EINVAL as non-fatal in general, so let's catch this specific case
and ignore it.

Reported by Reza Mohammadi on the mailing list.  Interestingly, it's kind of
hard to trigger this crash since the client would have to request the
connection, and that connection shouldn't exist because the original client
program would have already gotten EINVAL.  But my MacOS machine can generate
such a connection, so a MacOS->Linux sshuttle could trigger this.
2011-04-24 22:15:20 -04:00
8 changed files with 118 additions and 56 deletions

View File

@ -63,7 +63,19 @@ This is how you use it:
on your client machine. You'll need root or sudo on your client machine. You'll need root or sudo
access, and python needs to be installed. access, and python needs to be installed.
- <tt>./sshuttle -r username@sshserver 0.0.0.0/0 -vv</tt> - The most basic use of sshuttle looks like:
<tt>./sshuttle -r username@sshserver 0.0.0.0/0 -vv</tt>
- There is a shortcut for 0.0.0.0/0 for those that value
their wrists
<tt>./sshuttle -r username@sshserver 0/0 -vv</tt>
- If you would also like your DNS queries to be proxied
through the DNS server of the server you are connect to:
<tt>./sshuttle --dns -rvv username@sshserver 0/0</tt>
The above is probably what you want to use to prevent
local network attacks such as Firesheep and friends.
(You may be prompted for one or more passwords; first, the (You may be prompted for one or more passwords; first, the
local password to become root using either sudo or su, and local password to become root using either sudo or su, and

View File

@ -198,7 +198,14 @@ def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
handlers.append(mux) handlers.append(mux)
expected = 'SSHUTTLE0001' expected = 'SSHUTTLE0001'
try: try:
v = 'x'
while v and v != '\0':
v = serversock.recv(1)
v = 'x'
while v and v != '\0':
v = serversock.recv(1)
initstring = serversock.recv(len(expected)) initstring = serversock.recv(len(expected))
except socket.error, e: except socket.error, e:
if e.args[0] == errno.ECONNRESET: if e.args[0] == errno.ECONNRESET:

115
do
View File

@ -8,14 +8,14 @@
# #
# By default, no output coloring. # By default, no output coloring.
GREEN="" green=""
BOLD="" bold=""
PLAIN="" plain=""
if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then
GREEN="$(printf '\033[32m')" green="$(printf '\033[32m')"
BOLD="$(printf '\033[1m')" bold="$(printf '\033[1m')"
PLAIN="$(printf '\033[m')" plain="$(printf '\033[m')"
fi fi
_dirsplit() _dirsplit()
@ -24,6 +24,13 @@ _dirsplit()
dir=${1%$base} dir=${1%$base}
} }
dirname()
(
_dirsplit "$1"
dir=${dir%/}
echo "${dir:-.}"
)
_dirsplit "$0" _dirsplit "$0"
export REDO=$(cd "${dir:-.}" && echo "$PWD/$base") export REDO=$(cd "${dir:-.}" && echo "$PWD/$base")
@ -54,87 +61,105 @@ fi
_find_dofile_pwd() _find_dofile_pwd()
{ {
DOFILE=default.$1.do dofile=default.$1.do
while :; do while :; do
DOFILE=default.${DOFILE#default.*.} dofile=default.${dofile#default.*.}
[ -e "$DOFILE" -o "$DOFILE" = default.do ] && break [ -e "$dofile" -o "$dofile" = default.do ] && break
done done
EXT=${DOFILE#default} ext=${dofile#default}
EXT=${EXT%.do} ext=${ext%.do}
BASE=${1%$EXT} base=${1%$ext}
} }
_find_dofile() _find_dofile()
{ {
PREFIX= local prefix=
while :; do while :; do
_find_dofile_pwd "$1" _find_dofile_pwd "$1"
[ -e "$DOFILE" ] && break [ -e "$dofile" ] && break
[ "$PWD" = "/" ] && break [ "$PWD" = "/" ] && break
TARGET=${PWD##*/}/$TARGET target=${PWD##*/}/$target
PREFIX=${PWD##*/}/$PREFIX tmp=${PWD##*/}/$tmp
prefix=${PWD##*/}/$prefix
cd .. cd ..
done done
BASE=$PREFIX$BASE base=$prefix$base
} }
_run_dofile() _run_dofile()
{ {
export DO_DEPTH="$DO_DEPTH " export DO_DEPTH="$DO_DEPTH "
export REDO_TARGET=$PWD/$TARGET export REDO_TARGET=$PWD/$target
local line1
set -e set -e
read line1 <"$PWD/$DOFILE" read line1 <"$PWD/$dofile"
cmd=${line1#"#!/"} cmd=${line1#"#!/"}
if [ "$cmd" != "$line1" ]; then if [ "$cmd" != "$line1" ]; then
/$cmd "$PWD/$DOFILE" "$@" >"$TARGET.tmp2" /$cmd "$PWD/$dofile" "$@" >"$tmp.tmp2"
else else
. "$PWD/$DOFILE" >"$TARGET.tmp2" :; . "$PWD/$dofile" >"$tmp.tmp2"
fi fi
} }
_do() _do()
{ {
DIR=$1 local dir=$1 target=$2 tmp=$3
TARGET=$2 if [ ! -e "$target" ] || [ -d "$target" -a ! -e "$target.did" ]; then
if [ ! -e "$TARGET" ] || [ -e "$TARGET/." -a ! -e "$TARGET.did" ]; then
printf '%sdo %s%s%s%s\n' \ printf '%sdo %s%s%s%s\n' \
"$GREEN" "$DO_DEPTH" "$BOLD" "$DIR$TARGET" "$PLAIN" >&2 "$green" "$DO_DEPTH" "$bold" "$dir$target" "$plain" >&2
echo "$PWD/$TARGET" >>"$DO_BUILT" echo "$PWD/$target" >>"$DO_BUILT"
DOFILE=$TARGET.do dofile=$target.do
BASE=$TARGET base=$target
EXT= ext=
[ -e "$TARGET.do" ] || _find_dofile "$TARGET" [ -e "$target.do" ] || _find_dofile "$target"
if [ ! -e "$DOFILE" ]; then if [ ! -e "$dofile" ]; then
echo "do: $TARGET: no .do file" >&2 echo "do: $target: no .do file" >&2
return 1 return 1
fi fi
[ ! -e "$DO_BUILD" ] || : >>"$TARGET.did" [ ! -e "$DO_BUILT" ] || [ ! -d "$(dirname "$target")" ] ||
( _run_dofile "$BASE" "$EXT" "$TARGET.tmp" ) : >>"$target.did"
RV=$? ( _run_dofile "$base" "$ext" "$tmp.tmp" )
if [ $RV != 0 ]; then rv=$?
if [ $rv != 0 ]; then
printf "do: %s%s\n" "$DO_DEPTH" \ printf "do: %s%s\n" "$DO_DEPTH" \
"$DIR$TARGET: got exit code $RV" >&2 "$dir$target: got exit code $rv" >&2
rm -f "$TARGET.tmp" "$TARGET.tmp2" rm -f "$tmp.tmp" "$tmp.tmp2"
return $RV return $rv
fi fi
mv "$TARGET.tmp" "$TARGET" 2>/dev/null || mv "$tmp.tmp" "$target" 2>/dev/null ||
! test -s "$TARGET.tmp2" || ! test -s "$tmp.tmp2" ||
mv "$TARGET.tmp2" "$TARGET" 2>/dev/null mv "$tmp.tmp2" "$target" 2>/dev/null
rm -f "$TARGET.tmp2" rm -f "$tmp.tmp2"
else else
echo "do $DO_DEPTH$TARGET exists." >&2 echo "do $DO_DEPTH$target exists." >&2
fi fi
} }
# Make corrections for directories that don't actually exist yet.
_dir_shovel()
{
local dir base
xdir=$1 xbase=$2 xbasetmp=$2
while [ ! -d "$xdir" -a -n "$xdir" ]; do
_dirsplit "${xdir%/}"
xbasetmp=${base}__$xbase
xdir=$dir xbase=$base/$xbase
echo "xbasetmp='$xbasetmp'" >&2
done
}
redo() redo()
{ {
for i in "$@"; do for i in "$@"; do
_dirsplit "$i" _dirsplit "$i"
( cd "$dir" && _do "$dir" "$base" ) || return 1 _dir_shovel "$dir" "$base"
dir=$xdir base=$xbase basetmp=$xbasetmp
( cd "$dir" && _do "$dir" "$base" "$basetmp" ) || return 1
done done
} }

View File

@ -130,7 +130,7 @@ class DnsProxy(Handler):
try: try:
self.sock.send(self.request) self.sock.send(self.request)
except socket.error, e: except socket.error, e:
if e.args[0] in [errno.ECONNREFUSED, errno.EHOSTUNREACH]: if e.args[0] in ssnet.NET_ERRS:
# might have been spurious; try again. # might have been spurious; try again.
# Note: these errors sometimes are reported by recv(), # Note: these errors sometimes are reported by recv(),
# and sometimes by send(). We have to catch both. # and sometimes by send(). We have to catch both.
@ -145,7 +145,7 @@ class DnsProxy(Handler):
try: try:
data = self.sock.recv(4096) data = self.sock.recv(4096)
except socket.error, e: except socket.error, e:
if e.args[0] in [errno.ECONNREFUSED, errno.EHOSTUNREACH]: if e.args[0] in ssnet.NET_ERRS:
# might have been spurious; try again. # might have been spurious; try again.
# Note: these errors sometimes are reported by recv(), # Note: these errors sometimes are reported by recv(),
# and sometimes by send(). We have to catch both. # and sometimes by send(). We have to catch both.
@ -173,7 +173,7 @@ def main():
debug1(' %s/%d\n' % r) debug1(' %s/%d\n' % r)
# synchronization header # synchronization header
sys.stdout.write('SSHUTTLE0001') sys.stdout.write('\0\0SSHUTTLE0001')
sys.stdout.flush() sys.stdout.flush()
handlers = [] handlers = []

2
ssh.py
View File

@ -85,7 +85,7 @@ def connect(ssh_cmd, rhostport, python, stderr, options):
pycmd = "'%s' -c '%s'" % (python, pyscript) pycmd = "'%s' -c '%s'" % (python, pyscript)
else: else:
pycmd = ("P=python2; $P -V 2>/dev/null || P=python; " pycmd = ("P=python2; $P -V 2>/dev/null || P=python; "
"\"$P\" -c '%s'") % pyscript "exec \"$P\" -c '%s'") % pyscript
argv = (sshl + argv = (sshl +
portl + portl +
ipv6flag + ipv6flag +

View File

@ -1,5 +1,10 @@
#!/bin/sh #!/bin/sh
DIR=$(dirname "$0") EXE=$0
for i in 1 2 3 4 5 6 7 8 9 10; do
[ -L "$EXE" ] || break
EXE=$(readlink "$EXE")
done
DIR=$(dirname "$EXE")
if python2 -V 2>/dev/null; then if python2 -V 2>/dev/null; then
exec python2 "$DIR/main.py" python2 "$@" exec python2 "$DIR/main.py" python2 "$@"
else else

View File

@ -40,7 +40,11 @@ cmd_to_name = {
CMD_DNS_REQ: 'DNS_REQ', CMD_DNS_REQ: 'DNS_REQ',
CMD_DNS_RESPONSE: 'DNS_RESPONSE', CMD_DNS_RESPONSE: 'DNS_RESPONSE',
} }
NET_ERRS = [errno.ECONNREFUSED, errno.ETIMEDOUT,
errno.EHOSTUNREACH, errno.ENETUNREACH,
errno.EHOSTDOWN, errno.ENETDOWN]
def _add(l, elem): def _add(l, elem):
@ -124,6 +128,12 @@ class SockWrapper:
return # already connected return # already connected
self.rsock.setblocking(False) self.rsock.setblocking(False)
debug3('%r: trying connect to %r\n' % (self, self.connect_to)) debug3('%r: trying connect to %r\n' % (self, self.connect_to))
if socket.inet_aton(self.connect_to[0])[0] == '\0':
self.seterr(Exception("Can't connect to %r: "
"IP address starts with zero\n"
% (self.connect_to,)))
self.connect_to = None
return
try: try:
self.rsock.connect(self.connect_to) self.rsock.connect(self.connect_to)
# connected successfully (Linux) # connected successfully (Linux)
@ -145,9 +155,7 @@ class SockWrapper:
elif e.args[0] == errno.EISCONN: elif e.args[0] == errno.EISCONN:
# connected successfully (BSD) # connected successfully (BSD)
self.connect_to = None self.connect_to = None
elif e.args[0] in [errno.ECONNREFUSED, errno.ETIMEDOUT, elif e.args[0] in NET_ERRS + [errno.EACCES, errno.EPERM]:
errno.EHOSTUNREACH, errno.ENETUNREACH,
errno.EACCES, errno.EPERM]:
# a "normal" kind of error # a "normal" kind of error
self.connect_to = None self.connect_to = None
self.seterr(e) self.seterr(e)

View File

@ -1,5 +1,10 @@
exec >&2 exec >&2
redo-ifchange runpython.c redo-ifchange runpython.c
gcc -Wall -o $3 runpython.c \ ARCHES=""
for d in /usr/libexec/gcc/darwin/*; do
ARCHES="$ARCHES -arch $(basename $d)"
done
gcc $ARCHES \
-Wall -o $3 runpython.c \
-I/usr/include/python2.5 \ -I/usr/include/python2.5 \
-lpython2.5 -lpython2.5