summaryrefslogtreecommitdiffstats
path: root/sshuttle/methods
diff options
context:
space:
mode:
authorScott Kuhl <kuhl@mtu.edu>2020-12-26 15:25:33 -0500
committerBrian May <brian@linuxpenguins.xyz>2020-12-28 10:21:56 +1100
commit6d4261e3f9de17720c07239d0370f14a6fed36a9 (patch)
tree12fdce0285335c9c1efa4ece8a2b24b5cd325c48 /sshuttle/methods
parent7c338866bf1806d0c14887ff7b44be1bdf97a277 (diff)
Refactor automatic method selection.
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.
Diffstat (limited to 'sshuttle/methods')
-rw-r--r--sshuttle/methods/__init__.py33
-rw-r--r--sshuttle/methods/ipfw.py11
-rw-r--r--sshuttle/methods/nat.py9
-rw-r--r--sshuttle/methods/nft.py7
-rw-r--r--sshuttle/methods/pf.py8
-rw-r--r--sshuttle/methods/tproxy.py9
6 files changed, 58 insertions, 19 deletions
diff --git a/sshuttle/methods/__init__.py b/sshuttle/methods/__init__.py
index 2c59904..a8fe938 100644
--- a/sshuttle/methods/__init__.py
+++ b/sshuttle/methods/__init__.py
@@ -3,7 +3,7 @@ import socket
import struct
import errno
import ipaddress
-from sshuttle.helpers import Fatal, debug3, which
+from sshuttle.helpers import Fatal, debug3
def original_dst(sock):
@@ -55,6 +55,12 @@ class BaseMethod(object):
return result
@staticmethod
+ def is_supported():
+ """Returns true if it appears that this method will work on this
+ machine."""
+ return False
+
+ @staticmethod
def get_tcp_dstip(sock):
return original_dst(sock)
@@ -102,16 +108,15 @@ def get_method(method_name):
def get_auto_method():
- if which('iptables'):
- method_name = "nat"
- elif which('nft'):
- method_name = "nft"
- elif which('pfctl'):
- method_name = "pf"
- elif which('ipfw'):
- method_name = "ipfw"
- else:
- raise Fatal(
- "can't find either iptables, nft or pfctl; check your PATH")
-
- return get_method(method_name)
+ debug3("Selecting a method automatically...\n")
+ # Try these methods, in order:
+ methods_to_try = ["nat", "nft", "pf", "ipfw"]
+ for m in methods_to_try:
+ method = get_method(m)
+ if method.is_supported():
+ debug3("Method '%s' was automatically selected.\n" % m)
+ return method
+
+ raise Fatal("Unable to automatically find a supported method. Check that "
+ "the appropriate programs are in your PATH. We tried "
+ "methods: %s" % str(methods_to_try))
diff --git a/sshuttle/methods/ipfw.py b/sshuttle/methods/ipfw.py
index 8b4aebc..bedaf3c 100644
--- a/sshuttle/methods/ipfw.py
+++ b/sshuttle/methods/ipfw.py
@@ -1,8 +1,8 @@
import os
import subprocess as ssubprocess
from sshuttle.methods import BaseMethod
-from sshuttle.helpers import log, debug1, debug3, \
- Fatal, family_to_string, get_env
+from sshuttle.helpers import log, debug1, debug2, debug3, \
+ Fatal, family_to_string, get_env, which
recvmsg = None
try:
@@ -253,3 +253,10 @@ class Method(BaseMethod):
ipfw_noexit('table', '124', 'flush')
ipfw_noexit('table', '125', 'flush')
ipfw_noexit('table', '126', 'flush')
+
+ def is_supported(self):
+ if which("ipfw"):
+ return True
+ debug2("ipfw method not supported because 'ipfw' command is "
+ "missing.\n")
+ return False
diff --git a/sshuttle/methods/nat.py b/sshuttle/methods/nat.py
index 18ec1fd..f8c9149 100644
--- a/sshuttle/methods/nat.py
+++ b/sshuttle/methods/nat.py
@@ -1,6 +1,6 @@
import socket
from sshuttle.firewall import subnet_weight
-from sshuttle.helpers import family_to_string
+from sshuttle.helpers import family_to_string, which, debug2
from sshuttle.linux import ipt, ipt_ttl, ipt_chain_exists, nonfatal
from sshuttle.methods import BaseMethod
@@ -124,3 +124,10 @@ class Method(BaseMethod):
result = super(Method, self).get_supported_features()
result.user = True
return result
+
+ def is_supported(self):
+ if which("iptables"):
+ return True
+ debug2("nat method not supported because 'iptables' command "
+ "is missing.\n")
+ return False
diff --git a/sshuttle/methods/nft.py b/sshuttle/methods/nft.py
index 1b127ef..eb287f0 100644
--- a/sshuttle/methods/nft.py
+++ b/sshuttle/methods/nft.py
@@ -2,6 +2,7 @@ import socket
from sshuttle.firewall import subnet_weight
from sshuttle.linux import nft, nonfatal
from sshuttle.methods import BaseMethod
+from sshuttle.helpers import debug2, which
class Method(BaseMethod):
@@ -113,3 +114,9 @@ class Method(BaseMethod):
result = super(Method, self).get_supported_features()
result.ipv6 = True
return result
+
+ def is_supported(self):
+ if which("nft"):
+ return True
+ debug2("nft method not supported because 'nft' command is missing.\n")
+ return False
diff --git a/sshuttle/methods/pf.py b/sshuttle/methods/pf.py
index 0ef0f46..d686904 100644
--- a/sshuttle/methods/pf.py
+++ b/sshuttle/methods/pf.py
@@ -12,7 +12,7 @@ from ctypes import c_char, c_uint8, c_uint16, c_uint32, Union, Structure, \
sizeof, addressof, memmove
from sshuttle.firewall import subnet_weight
from sshuttle.helpers import debug1, debug2, debug3, Fatal, family_to_string, \
- get_env
+ get_env, which
from sshuttle.methods import BaseMethod
@@ -491,3 +491,9 @@ class Method(BaseMethod):
return True
else:
return False
+
+ def is_supported(self):
+ if which("pfctl"):
+ return True
+ debug2("pf method not supported because 'pfctl' command is missing.\n")
+ return False
diff --git a/sshuttle/methods/tproxy.py b/sshuttle/methods/tproxy.py
index e7dba5e..6c3cf61 100644
--- a/sshuttle/methods/tproxy.py
+++ b/sshuttle/methods/tproxy.py
@@ -3,7 +3,7 @@ from sshuttle.firewall import subnet_weight
from sshuttle.helpers import family_to_string
from sshuttle.linux import ipt, ipt_ttl, ipt_chain_exists
from sshuttle.methods import BaseMethod
-from sshuttle.helpers import debug1, debug3, Fatal
+from sshuttle.helpers import debug1, debug2, debug3, Fatal, which
recvmsg = None
try:
@@ -294,3 +294,10 @@ class Method(BaseMethod):
if ipt_chain_exists(family, table, divert_chain):
_ipt('-F', divert_chain)
_ipt('-X', divert_chain)
+
+ def is_supported(self):
+ if which("iptables") and which("ip6tables"):
+ return True
+ debug2("tproxy method not supported because 'iptables' "
+ "or 'ip6tables' commands are missing.\n")
+ return False