Fix parsing of hostnames to allow ssh aliases defined in ssh configs) (#418)

* Fix parsing of hostnames to allow ssh aliases defined in ssh configs)

* nicer formatting, pep8 applied

* Properly parse IPv6 addresses with port specification

* Now also handles hostnames with port specified and IPv6 addresses without port  properly

* Updated parameter description for the remotehost specification

* Make the urlparse import backwards compatible to python2

Co-authored-by: Tobi <tobi-git@grimm.gr>
This commit is contained in:
tobigrimm 2020-04-25 01:40:39 +02:00 committed by GitHub
parent 580462156e
commit 966fd0c523
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 32 deletions

View File

@ -177,9 +177,9 @@ parser.add_argument(
) )
parser.add_argument( parser.add_argument(
"-r", "--remote", "-r", "--remote",
metavar="[USERNAME@]ADDR[:PORT]", metavar="[USERNAME[:PASSWORD]@]ADDR[:PORT]",
help=""" help="""
ssh hostname (and optional username) of remote %(prog)s server ssh hostname (and optional username and password) of remote %(prog)s server
""" """
) )
parser.add_argument( parser.add_argument(

View File

@ -6,6 +6,14 @@ import zlib
import imp import imp
import subprocess as ssubprocess import subprocess as ssubprocess
import shlex import shlex
import ipaddress
# ensure backwards compatiblity with python2.7
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
import sshuttle.helpers as helpers import sshuttle.helpers as helpers
from sshuttle.helpers import debug2 from sshuttle.helpers import debug2
@ -61,53 +69,64 @@ def empackage(z, name, data=None):
def parse_hostport(rhostport): def parse_hostport(rhostport):
# default define variable """
port = "" parses the given rhostport variable, looking like this:
username = re.split(r'\s*:', rhostport)[0]
# Fix #410 bad username error detect [username[:password]@]host[:port]
if "@" in username:
username = re.split(r'\s*@', rhostport)[0]
if only host is given, can be a hostname, IPv4/v6 address or a ssh alias
from ~/.ssh/config
and returns a tuple (username, password, port, host)
"""
# default port for SSH is TCP port 22
port = 22
username = None
password = None password = None
host = None host = rhostport
try: if "@" in host:
password = re.split(r'\s*:', rhostport)[1] # split username (and possible password) from the host[:port]
if "@" in password: username, host = host.split("@")
password = password.split("@")[0] # Fix #410 bad username error detect
except (IndexError, TypeError): # username cannot contain an @ sign in this scenario
pass if ":" in username:
# this will even allow for the username to be empty
username, password = username.split(":")
if password is None or "@" in password: if ":" in host:
# default define password # IPv6 address and/or got a port specified
password = None
host = password
if host is None: # If it is an IPv6 adress with port specification,
# split for ipv4 or ipv6 # then it will look like: [::1]:22
host = "{}".format(re.split(r'\s*@', rhostport)[1])
# try if port define
try: try:
# Fix #410 detect host:port # try to parse host as an IP adress,
port = re.split(r'\s*:', host)[1] # if that works it is an IPv6 address
host = re.split(r'\s*:', host)[0] host = ipaddress.ip_address(host)
except IndexError: except ValueError:
pass # if that fails parse as URL to get the port
parsed = urlparse('//{}'.format(host))
try:
host = ipaddress.ip_address(parsed.hostname)
except ValueError:
# else if both fails, we have a hostname with port
host = parsed.hostname
port = parsed.port
if port == "":
port = 22
if password is None or len(password) == 0: if password is None or len(password) == 0:
password = None password = None
return username, password, port, host return username, password, port, host
def connect(ssh_cmd, rhostport, python, stderr, options): def connect(ssh_cmd, rhostport, python, stderr, options):
username, password, port, host = parse_hostport(rhostport) username, password, port, host = parse_hostport(rhostport)
if username:
rhost = "{}@{}".format(username, host) rhost = "{}@{}".format(username, host)
else:
rhost = host
z = zlib.compressobj(1) z = zlib.compressobj(1)
content = readfile('sshuttle.assembler') content = readfile('sshuttle.assembler')