Since sshuttle's TTL code was removed in a recent commit, this code
will cause sshuttle to exit when the host specified with -r is
actually the localhost.
Previously, it was possible to run sshuttle locally without using ssh
and connecting to a remote server. In this configuration, traffic was
redirected to the sshuttle server running on the localhost. However,
the firewall needed to distinguish between traffic leaving the
sshuttle server and traffic that originated from the machine that
still needed to be routed through the sshuttle server. The TTL of the
packets leaving the sshuttle server were manipulated to indicate to
the firewall what should happen. The TTL was adjusted for all packets
leaving the sshuttle server (even if it wasn't necessary because the
server and client were running on different machines).
Changing the TTL caused trouble and some machines, and
the --ttl option was added as a workaround to change how the TTL was
set for traffic leaving sshuttle. All of this added complexity to the
code for a feature (running the server on localhost) that is likely
only used for testing and rarely used by others.
This commit updates the associated documentation, but doesn't fully
fix the ipfw method since I am unable to test that.
This change will also make sshuttle fail to work if -r is used to
specify a localhost. Pull request #610 partially addresses that issue.
For example, see: #240, #490, #660, #606.
If pfctl returns non-zero when setting up the firewall, sshuttle exits
and indicates the exit status code. This patch makes it so the output
of pfctl is also printed so the user can get a better idea of what
caused the problem.
For example: issue #491
If an exception occurs in hostwatch, sshuttle exits. Problems
read/writing the ~/.sshuttle.hosts cache file on the remote machine
would therefore cause sshuttle to exit. With this patch, we simply
continue running without writing/reading the cache file in the remote
home directory. This serves as an alternate fix for
pull request #322 which proposed storing the cache file elsewhere.
A list of included changes:
- If we can't read or write the host cache file on the server,
continue running. Hosts can be collected through the netstat,
/etc/hosts, etc and the information can be reconstructed each run if
a cache file isn't available to read. We write a log() message when
this occurs.
- Add additional types of exceptions to handle.
- Continue even if we cannot read /etc/hosts on the server.
- Update man page to mention the cache file on the remote host.
- Indicate that messages are related to remote host instead of local
host.
- Add comments and descriptions to the code.
The output in the examples provided in the man page hadn't been
updated as sshuttle changed its output over time.
The example of testing sshuttle without a remote host was removed. It
was the first example previously and it is something that is unlikely
users will wish to do.
Also:
- Update some --help messages.
- Manpage: Fix a typo.
- Manpage: Mention that host specified with -r can be an ssh alias.
- Eliminate variable only used once.
11 years ago in commit 384d0e7c1d,
hostwatch was updated to use netstat to find hosts, and
_check_smb()/_check_nmb() were edited to immediately return. This
patch removes all of the unused code in these two functions.
Even when --tmark was used, the iptables code always used '1' for the
mark. This patch corrects the problem.
Previously, it wasn't clear if the tmark should be supplied in
hexadecimal or as an integer. This makes it use hexadecimal, checks
that the input is hexadecimal, and updates the associated
documentation.
This patch also makes --ttl information get passed to the firewall in
a way that matches how other information gets passed. The ttl and
tmark information are passed next to each other in many places and
this patch also makes the order consistent.
If the user specifies --to-ns (tells the remote server which DNS
server to use for lookups coming from sshuttle), then either --ns-host
or --dns need to also be used (route DNS requests through sshuttle).
A previous commit incorrectly made it so --to-ns and --ns-host
couldn't be successfully used together.
Attempts to fix#641.
Issue #631 suggests that we should warn about users who add sshuttle
to sudoers because it isn't obvious that when a user can run sshuttle
as root, they can run any command as root using sshuttle's -e or
--ssh-cmd parameters.
This patch adds a comment that warns about this problem to the sudoers
file. It also prints the warning to the console if the user uses an
option that writes the data directly to the file. This patch also
causes the output of the sudoers-add command to be printed to the
console so that the user can see the name of the file that was
created.
There is room for improvement: Warnings could be added to the
documentation and/or these parameters could be removed entirely.
It is possible for DNS requests to go through systemd's DNS resolution
system (which includes a cache) before sshuttle has an opportunity to
intercept the requests. The DNS entries in the cache may become
outdated when sshuttle starts or exits. This patch fixes the problem
by flushing the cache when sshuttle firewall starts and exits.
This patch checks to see if the client and the server are running on
the same machine. The client creates a temporary file that the server
then looks for. If the server finds the file, it knows it is on the
same machine as the client and it deletes the file. Next, if the
client detects that the file has been deleted by the server, it
assumes that it is running on the same machine as the server.
This check is necessary since a user may specify a remote host with
"-r" that actually points back to the same machine the client is on.
This commit uses tempfile.mkstemp() which was added in Python 2.3.
Functionally, this commit does nothing except add a debug message
about if the client and server are on the same machine. It also sets a
variable which contains this information for potential future use.
Potential future uses include...
1) If the TTL hack is removed, this can be used to print a error
message since running the client and server on the same machine would
no longer be supported.
2) If the TTL hack is continued, we could disable the hack when the
client and the server are on different machines.
Here, we try to open the pidfile for writing prior to forking so that
the exit code can properly indicate to the user that there was a
problem. No error messages are printed to the console in this case
because when --daemon implies --syslog. So, the syslog will contain
the message indicating that the pidfile wasn't writeable.
Fixes bug #598.
In instances where a cluster pod in a local VM needs to access a server
that is sshuttle'd from the host, since the packets arriving at the host
already made a hop, their TTL is 63 and so get ignored by sshuttle.
Allowing an override of the firewall TTL rule allows the packets to go
through.
sshuttle has a --latency-buffer-size parameter, but it only changes
the buffer size on the client and not the server. Therefore,
increasing or decreasing the number doesn't make any change in
download performance (like the documentation indicates that it should).
You can test this change by setting up a sshuttle connection and
downloading a large file through sshuttle. With this patch, you should
find that increasing --latency-buffer-size increases the download
speed. Without the patch, the parameter should have little impact on
performance.
If you use the tproxy method with a large subnet (such as 0/0), then
(1) you may not receive UDP packets that sshuttle/tproxy can handle
and (2) you are unable to connect to your machine using an IP that
your computer recognizes as its own.
To resolve those issues, any traffic to an IP that the host knows is
local, does not go through the sshuttle chains.
* Improve error messages related to sshuttle server.
There are many GitHub issues related to the cryptic message:
fatal: expected server init string 'SSHUTTLE0001'; got b''
The code that prints that message is after another check that is
intended to verify that the server is still running. This code was
faulty since the server is still running when rv==None (but exited
when rv==0).
I corrected this problem and then investigated ways to clarify the
error message. I added additional exit codes for the server: 97 (exec
in the shell returned), 98 (the python exec() function called
returned). The end result is that the cryptic error message above will
now print a more appropriate error message that should aid in
debugging.
I also changed the server so that it catches Fatal() and exits with
exit code 99 (like the client does). Previously, it was just an
unhandled exception on the server.
I suspect some of the error messages were caused by restricted shells.
I also investigated and added comments about how sshuttle might behave
if it is being run on a server that has a restricted shell.
This commit also replaces a couple of exit() calls in cmdline.py with
'return' since exit() is intended for interactive use. This change
doesn't impact the server.
* Remind user to exclude remote host when server exits with 255.
This commit rewrites the log() function so that it will append a
newline at the end of the message if none is present. It doesn't make
sense to print a log message without a newline since the next log
message (which will write a prefix) expects to be starting at the
beginning of a line.
Although it isn't strictly necessary, this commit also removes any
newlines at the ends of messages. If I missed any, including the
newline at the end of the message will continue to work as it did
before.
Previously, some calls were missing the newline at the end even though
including it was necessary for subsequent messages to appear
correctly.
This code also cleans up some redundant prefixes. The log() method
will prepend the prefix and the different processes should set their
prefix as soon as they start.
Multiline messages are still supported (although the prefix for the
additional lines was changed to match the length of the prefix used
for the first line).
When users put parameters in a config file and pass them to sshuttle
using '@', they might copy the quotes from the command line into the
config file. This fix first ensures that we strip whitespace from the
beginning/end of each line in the config file. Then, if the line
begins and ends with a matching quote character, strip those too.
Fixes#573.
Add an "is_supported()" function to the different methods so that each
method can include whatever logic they wish to indicate if they are
supported on a particular machine. Previously, methods/__init__.py
contained all of the logic for selecting individual methods. Now, it
iterates through a list of possible options and stops on the first
method that it finds that is_supported().
Currently, the decision is made based on the presence of programs in
the PATH. In the future, things such as the platform sshuttle is
running on could be considered.
The server should just read from resolv.conf to find DNS servers to
use. This restores this behavior after the previous commit changed it.
The client now reads both /etc/resolv.conf and
/run/systemd/resolve/resolv.conf. The latter is required to more
reliably intercept regular DNS requests that systemd-resolved makes.
This commit makes two fixes:
1. If an IPv6 DNS server is used, an nft rule had "ip6 protocol" in it
which is invalid and caused sshuttle to exit.
2. I modified detection of udp vs tcp to follow the recommendation at
https://superuser.com/questions/1560376/match-ipv6-protocol-using-nftables
I also re-arranged the code slightly to reduce the number of
if-statements.
Some methods are unable to determine the destination address of DNS
packets that we capture. When this happens, change the message so it
just shows where the DNS requests are from.
Previously, we would find DNS servers we wish to intercept traffic on
by reading /etc/resolv.conf. On systems using systemd-resolved,
/etc/resolv.conf points to localhost and then systemd-resolved
actually uses the DNS servers listed in
/run/systemd/resolve/resolv.conf. Many programs will route the DNS
traffic through localhost as /etc/resolv.conf indicates and sshuttle
would capture it. However, systemd-resolved also provides other
interfaces for programs to resolve hostnames besides the localhost
server in /etc/resolv.conf.
This patch adds systemd-resolved's servers into the list of DNS
servers when --dns is used.
Note that sshuttle will continue to fail to intercept any traffic sent
to port 853 for DNS over TLS (which systemd-resolved also supports).
For more info, see:
sshuttle issue #535https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.htmlhttps://github.com/systemd/systemd/issues/6076
This patch attempts to fix (or aid in debugging) issue #350.
sshuttle didn't explicitly search /sbin and /usr/sbin and they may be
missing in the user's PATH. If PATH is missing, these folders wouldn't
be searched either. There was also a program_exists function which is
redundant to which(). This consolidates everything into the helpers.py
file.
This patch introduces get_path() to return PATH + some extra hardcoded
paths. A new get_env() function can be called to create a consistent
environment when calling external programs. The new which() wrapper
function also ensures we use the same set of paths.
If -vv is supplied, messages clearly indicate the programs we are
looking for, if they are found, and where we looked if we failed to
find them.
I haven't tested the changes to ipfw or pf.
This works for me but needs testing by others. Remember to specify a
::0/0 subnet or similar to route IPv6 through sshuttle.
I'm adding this to nft before nat since it is not sshuttle's default
method on Linux. Documentation updates may be required too.
This patch uses the ipaddress module, but that appears to be included
since Python 3.3.