Compare commits

...

9 Commits

Author SHA1 Message Date
a8b71f6387 Move nested functions to top level. 2011-05-31 00:42:48 -04:00
4bfcd7091d Send DNS request back on same sock we received it on. 2011-05-31 00:39:17 -04:00
bd489b3319 Pass socket through to handlers. Required for IPv6 support. 2011-05-31 00:39:17 -04:00
8ab5ef283d ssnet.py: deal with a possible connect/getsockopt(SO_ERROR) race.
Seems to affect Linux servers.  Ed Maste says the patch fixes it for him.
2011-05-29 22:42:16 -04:00
e67208a294 helpers.py: errno is used by this module, but not imported. 2011-05-15 17:35:53 -04:00
7859be13c2 ui-macos/bits/runpython.do: skip ppc64 architecture.
I don't have a Mac that can build it.  Hopefully ppc will run fine on ppc64.
2011-05-07 23:19:52 -04:00
f313d50690 ui-macos/bits/runpython.do: report which platforms we're compiling for.
Just as a quick reminder, in case you're building a fat binary and you don't
have all the architectures actually installed.
2011-05-07 23:16:42 -04:00
15e26d2e0e README.md: fix little bug
The ssh hostname should immediately follow the -r parameter.
2011-05-07 23:16:42 -04:00
e2ec475de3 ui-macos/models.py: fix a compatibility problem on MacOS for PPC.
@objc.accessor isn't the right thing to use for a Core Data Validation
function.  Yowee, PyObjc sure is non-obvious.
2011-05-07 23:16:42 -04:00
6 changed files with 84 additions and 61 deletions

View File

@ -72,7 +72,7 @@ This is how you use it:
- If you would also like your DNS queries to be proxied - If you would also like your DNS queries to be proxied
through the DNS server of the server you are connect to: through the DNS server of the server you are connect to:
<tt>./sshuttle --dns -rvv username@sshserver 0/0</tt> <tt>./sshuttle --dns -vvr username@sshserver 0/0</tt>
The above is probably what you want to use to prevent The above is probably what you want to use to prevent
local network attacks such as Firesheep and friends. local network attacks such as Firesheep and friends.

116
client.py
View File

@ -175,6 +175,65 @@ class FirewallClient:
raise Fatal('cleanup: %r returned %d' % (self.argv, rv)) raise Fatal('cleanup: %r returned %d' % (self.argv, rv))
def onaccept(listener, mux, handlers):
global _extra_fd
try:
sock,srcip = listener.accept()
except socket.error, e:
if e.args[0] in [errno.EMFILE, errno.ENFILE]:
debug1('Rejected incoming connection: too many open files!\n')
# free up an fd so we can eat the connection
os.close(_extra_fd)
try:
sock,srcip = listener.accept()
sock.close()
finally:
_extra_fd = os.open('/dev/null', os.O_RDONLY)
return
else:
raise
dstip = original_dst(sock)
debug1('Accept: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
dstip[0],dstip[1]))
if dstip[1] == listener.getsockname()[1] and islocal(dstip[0]):
debug1("-- ignored: that's my address!\n")
sock.close()
return
chan = mux.next_channel()
if not chan:
log('warning: too many open channels. Discarded connection.\n')
sock.close()
return
mux.send(chan, ssnet.CMD_CONNECT, '%s,%s' % dstip)
outwrap = MuxWrapper(mux, chan)
handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
dnsreqs = {}
def dns_done(chan, data):
peer,sock,timeout = dnsreqs.get(chan) or (None,None,None)
debug3('dns_done: channel=%r peer=%r\n' % (chan, peer))
if peer:
del dnsreqs[chan]
debug3('doing sendto %r\n' % (peer,))
sock.sendto(data, peer)
def ondns(listener, mux, handlers):
pkt,peer = listener.recvfrom(4096)
now = time.time()
if pkt:
debug1('DNS request from %r: %d bytes\n' % (peer, len(pkt)))
chan = mux.next_channel()
dnsreqs[chan] = peer,listener,now+30
mux.send(chan, ssnet.CMD_DNS_REQ, pkt)
mux.channels[chan] = lambda cmd,data: dns_done(chan,data)
for chan,(peer,sock,timeout) in dnsreqs.items():
if timeout < now:
del dnsreqs[chan]
debug3('Remaining DNS requests: %d\n' % len(dnsreqs))
def _main(listener, fw, ssh_cmd, remotename, python, latency_control, def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
dnslistener, seed_hosts, auto_nets, dnslistener, seed_hosts, auto_nets,
syslog, daemon): syslog, daemon):
@ -255,63 +314,10 @@ def _main(listener, fw, ssh_cmd, remotename, python, latency_control,
fw.sethostip(name, ip) fw.sethostip(name, ip)
mux.got_host_list = onhostlist mux.got_host_list = onhostlist
def onaccept(): handlers.append(Handler([listener], lambda: onaccept(listener, mux, handlers)))
global _extra_fd
try:
sock,srcip = listener.accept()
except socket.error, e:
if e.args[0] in [errno.EMFILE, errno.ENFILE]:
debug1('Rejected incoming connection: too many open files!\n')
# free up an fd so we can eat the connection
os.close(_extra_fd)
try:
sock,srcip = listener.accept()
sock.close()
finally:
_extra_fd = os.open('/dev/null', os.O_RDONLY)
return
else:
raise
dstip = original_dst(sock)
debug1('Accept: %s:%r -> %s:%r.\n' % (srcip[0],srcip[1],
dstip[0],dstip[1]))
if dstip[1] == listener.getsockname()[1] and islocal(dstip[0]):
debug1("-- ignored: that's my address!\n")
sock.close()
return
chan = mux.next_channel()
if not chan:
log('warning: too many open channels. Discarded connection.\n')
sock.close()
return
mux.send(chan, ssnet.CMD_CONNECT, '%s,%s' % dstip)
outwrap = MuxWrapper(mux, chan)
handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
handlers.append(Handler([listener], onaccept))
dnsreqs = {}
def dns_done(chan, data):
peer,timeout = dnsreqs.get(chan) or (None,None)
debug3('dns_done: channel=%r peer=%r\n' % (chan, peer))
if peer:
del dnsreqs[chan]
debug3('doing sendto %r\n' % (peer,))
dnslistener.sendto(data, peer)
def ondns():
pkt,peer = dnslistener.recvfrom(4096)
now = time.time()
if pkt:
debug1('DNS request from %r: %d bytes\n' % (peer, len(pkt)))
chan = mux.next_channel()
dnsreqs[chan] = peer,now+30
mux.send(chan, ssnet.CMD_DNS_REQ, pkt)
mux.channels[chan] = lambda cmd,data: dns_done(chan,data)
for chan,(peer,timeout) in dnsreqs.items():
if timeout < now:
del dnsreqs[chan]
debug3('Remaining DNS requests: %d\n' % len(dnsreqs))
if dnslistener: if dnslistener:
handlers.append(Handler([dnslistener], ondns)) handlers.append(Handler([dnslistener], lambda: ondns(dnslistener, mux, handlers)))
if seed_hosts != None: if seed_hosts != None:
debug1('seed_hosts: %r\n' % seed_hosts) debug1('seed_hosts: %r\n' % seed_hosts)

View File

@ -1,4 +1,4 @@
import sys, os, socket import sys, os, socket, errno
logprefix = '' logprefix = ''
verbose = 0 verbose = 0

View File

@ -152,6 +152,17 @@ class SockWrapper:
debug3('%r: fixed connect result: %s\n' % (self, e)) debug3('%r: fixed connect result: %s\n' % (self, e))
if e.args[0] in [errno.EINPROGRESS, errno.EALREADY]: if e.args[0] in [errno.EINPROGRESS, errno.EALREADY]:
pass # not connected yet pass # not connected yet
elif e.args[0] == 0:
# connected successfully (weird Linux bug?)
# Sometimes Linux seems to return EINVAL when it isn't
# invalid. This *may* be caused by a race condition
# between connect() and getsockopt(SO_ERROR) (ie. it
# finishes connecting in between the two, so there is no
# longer an error). However, I'm not sure of that.
#
# I did get at least one report that the problem went away
# when we added this, however.
self.connect_to = None
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

View File

@ -1,9 +1,14 @@
exec >&2 exec >&2
redo-ifchange runpython.c redo-ifchange runpython.c
ARCHES="" ARCHES=""
printf "Platforms: "
for d in /usr/libexec/gcc/darwin/*; do for d in /usr/libexec/gcc/darwin/*; do
ARCHES="$ARCHES -arch $(basename $d)" PLAT=$(basename "$d")
[ "$PLAT" != "ppc64" ] || continue # fails for some reason on my Mac
ARCHES="$ARCHES -arch $PLAT"
printf "$PLAT "
done done
printf "\n"
gcc $ARCHES \ gcc $ARCHES \
-Wall -o $3 runpython.c \ -Wall -o $3 runpython.c \
-I/usr/include/python2.5 \ -I/usr/include/python2.5 \

View File

@ -3,6 +3,7 @@ import my
configchange_callback = setconnect_callback = None configchange_callback = setconnect_callback = None
objc_validator = objc.signature('@@:N^@o^@')
def config_changed(): def config_changed():
@ -39,7 +40,7 @@ class SshuttleNet(NSObject):
def setSubnet_(self, v): def setSubnet_(self, v):
self._k_subnet = v self._k_subnet = v
config_changed() config_changed()
@objc.accessor @objc_validator
def validateSubnet_error_(self, value, error): def validateSubnet_error_(self, value, error):
#print 'validateSubnet!' #print 'validateSubnet!'
return True, _validate_ip(value), error return True, _validate_ip(value), error
@ -49,7 +50,7 @@ class SshuttleNet(NSObject):
def setWidth_(self, v): def setWidth_(self, v):
self._k_width = v self._k_width = v
config_changed() config_changed()
@objc.accessor @objc_validator
def validateWidth_error_(self, value, error): def validateWidth_error_(self, value, error):
#print 'validateWidth!' #print 'validateWidth!'
return True, _validate_width(value), error return True, _validate_width(value), error
@ -118,7 +119,7 @@ class SshuttleServer(NSObject):
self._k_host = v self._k_host = v
self.setTitle_(None) self.setTitle_(None)
config_changed() config_changed()
@objc.accessor @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)
while value.startswith('-'): while value.startswith('-'):