...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...)
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.
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.
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.
A few people have reported that they have one or more invalid DNS servers in
/etc/resolv.conf, which they don't notice because the normal resolver
library just skips the broken ones. sshuttle would abort because it got an
unexpected socket error, which isn't so good.
Bug reported by Ed Maste. The fix in later versions of python is documented
here:
http://mail.python.org/pipermail/python-bugs-list/2006-August/034667.html
We're basically just doing the same thing when we see EINVAL. Note that
this doesn't happen on Linux because connect() is more forgiving.
So let's use %s instead of %r to print it, so that log messages can be more
useful. This only affects one message at debug3 for now, so it's not too
exciting.
According to at least one report, there are some slightly insane servers out
there that have /dev/null set to non-user-writable. This is totally broken,
but we want sshuttle to work with as many servers as possible, so let's fake
it up a bit instead.
We don't try to avoid /dev/null on the client; sshuttle needs root access
anyway, and if you're root, you can just fix your stupid /dev/null
permissions.
Including a copy of minimal/do as 'do' in the top directory. To build, just
run './do' or 'make'.
This also builds the ui-macos directory automatically if you're on MacOS.
If the previous run of sshuttle didn't manage to clean up after itself, it
might have left the sshuttle-12300 chain intact, but the OUTPUT chain might
not refer to it anymore. That would cause the *next* run of sshuttle to
barf when trying to delete the OUTPUT entry, and then never get to the part
where it just tries to delete the old chain so it can continue.
Now only the last delete command (the one that actually deletes the chain)
is fatal if it fails; the others just print a scary message, but that should
only happen once in your life if you're unlucky.
If this sysctl isn't set to 0 at the time your network interface is brought
up, and we later change it, then the MacOS (10.6.6 at least) ARP table gets
totally confused and networking stops working about 15 minutes later, until
you down and re-up the interface. The symptom is that pings outside your
LAN would give results like this:
ping: sendto: no route to host
and "arp -a -n" would show *two* entries for your default gateway instead of
just one.
sshuttle was helpfully putting the sysctl back the way it was when it shuts
down, so you would fix your network by downing the interface, so sshuttle
would abort and change the sysctl back, then you would re-up the interface,
then restart sshuttle, and sshuttle would change the sysctl back and restart
the cycle: it would break again a few minutes later.
That's annoying, and it gives sshuttle a bad reputation for being the thing
that breaks your network. I can't find a *really* good workaround for the
bug, so barring that, let's just permanently set the sysctl to 0 and not
change it back on exit. That should just leave your computer back how it
worked in MacOS 10.5, as far as I know, which seems harmless. At least I've
been running my Mac that way for a few days and I haven't seen any
weirdness.
Now, doing *that* would still mean that the first sshuttle session after a
reboot would still break the network, since sysctl changes are lost on
reboot. Thus, let's be extra hardcore and write it to /etc/sysctl.conf so
that it goes the way we want it after a reboot. Thus, sshuttle should break
your network at most once. Which still sucks, but hopefully nobody will
notice.
I think some connections you'll want to optimize for latency, and others for
bandwidth. Probably.
Also, use a dropdown box instead of a checkbox; that way we can make it more
clear what each of the settings means.
While we're here, adjust all the anchor settings for the different display
items so that resizing the dialog box works sensibly.
This version is a bit limited: it always only connects back to itself, which
is always on 127.0.0.1. It also doesn't really find any problems, other
than odd behaviour when Linux runs out of available port numbers after a
while.
This makes it easier to actually test what happens when channel numbers wrap
around. The good news: it works.
However, I did find a bug where sshuttle would die if we completely ran out
of available channel numbers because so many of them were open. This would
never realistically happen at the default of 65535 channels (we'd run out of
file descriptors first), but it's still a bug, so let's handle it by just
dropping the connection when it happens.
* dns:
dns on MacOS: use divert sockets instead of 'fwd' rules.
client.py: do DNS listener on the same port as the TCP listener.
Move client._islocal() to helpers.islocal() in preparation for sharing.
dns: add support for MacOS (but it doesn't work...)
Oops, dns_done() crashed if the request had already been timed out.
dns: trim DNS channel handlers after a response, or after a timeout.
dns: extract 'nameserver' lines from /etc/resolv.conf
Extremely basic, but functional, DNS proxying support (--dns option)
It turns out diverting UDP sockets is pretty easy compared to TCP (which
makes it all the more embarrassing that they screwed up 'fwd' support for
UDP and not TCP, but oh well). So let's use divert sockets instead of
transproxy for our DNS packets.
This is a little tricky because we have to do it all in firewall.py, since
divert sockets require root access, and only firewall.py has root access.
UDP and TCP have separate port namespaces, so to make it easier to keep
track of what's going on, just use the same transproxy port number for both.
We still need two sockets, but now tcpdumps are easier to understand.
...because stupid MacOS ipfw 'fwd' rules don't work quite right with udp.
It can intercept packets bound for remote hosts, but it doesn't correctly
rewrite the port number from its original to the new socket, so it gets
dropped by the local kernel anyway.
That is, a packet to 1.2.3.4:53 should be redirected to, say,
127.0.0.1:9999, the local DNS listener socket. But instead, it gets sent to
127.0.0.1:53, which nobody is listening on, so it gets eaten.
Sigh.