U
    烳dm                    @   s2  d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	m	Z	 ddl
mZ ddlZejd dk rddlZddlZefZeZnddlZddlZeZeZdZdZdZd	Zd
Zdae ZdddddZ ej!Z"dZ#e$e#d dZ%ej&dkrej'nej(Z)dZ%ej*+e%dZ,dd Z-dd Z.dd Z/dBddZ0dCddZ1dDdd Z2dEd!d"Z3d#d$ Z4d%d& Z5d'd( Z6G d)d* d*e7Z8G d+d, d,e8Z9G d-d. d.ej:Z;G d/d0 d0ej(Z<G d1d2 d2ej=e<Z>G d3d4 d4e)Z?G d5d6 d6ej=e?Z@G d7d8 d8eAZBd9d: ZCd;d< ZDdFd=d>ZEdGd?d@ZFeGdAkr.eF  dS )Ha  
*sshtunnel* - Initiate SSH tunnels via a remote gateway.

``sshtunnel`` works by opening a port forwarding SSH connection in the
background, using threads.

The connection(s) are closed when explicitly calling the
:meth:`SSHTunnelForwarder.stop` method or using it as a context.

    N)select)hexlify   z0.4.0Zpahaz皙?g      $@T   ssh_address_or_hostssh_pkeymute_exceptions)ssh_addressssh_hostssh_private_key/raise_exception_if_any_forwarder_have_a_problemTRACEz~/.sshposixconfigc                 C   s"   t | tstdt| jd S )NzIP is not a string ({0}))
isinstancestring_typesAssertionErrorformattype__name__)host r   F/var/www/html/myproject/myenv/lib/python3.8/site-packages/sshtunnel.py
check_hostN   s    r   c                 C   s,   t | tstd| dks(td| d S )NzPORT is not a numberr   zPORT < 0 ({0}))r   intr   r   )portr   r   r   
check_portT   s    r   c                 C   s   t | tr$t| d  t| d  nbt | trrtjdkr@tdtj	| st
tj| tjstd| ntdt| jdS )a  
    Check if the format of the address is correct

    Arguments:
        address (tuple):
            (``str``, ``int``) representing an IP address and port,
            respectively

            .. note::
                alternatively a local ``address`` can be a ``str`` when working
                with UNIX domain sockets, if supported by the platform
    Raises:
        ValueError:
            raised when address has an incorrect format

    Example:
        >>> check_address(('127.0.0.1', 22))
    r   r   r   z-Platform does not support UNIX domain socketsz.ADDRESS not a valid socket domain socket ({0})z9ADDRESS is not a tuple, string, or character buffer ({0})N)r   tupler   r   r   osname
ValueErrorpathexistsaccessdirnameW_OKr   r   r   addressr   r   r   check_addressY   s    


r)   Fc                 C   sJ   t dd | D st|r4tdd | D r4td| D ]}t| q8dS )a  
    Check if the format of the addresses is correct

    Arguments:
        address_list (list[tuple]):
            Sequence of (``str``, ``int``) pairs, each representing an IP
            address and port respectively

            .. note::
                when supported by the platform, one or more of the elements in
                the list can be of type ``str``, representing a valid UNIX
                domain socket

        is_remote (boolean):
            Whether or not the address list
    Raises:
        AssertionError:
            raised when ``address_list`` contains an invalid element
        ValueError:
            raised when any address in the list has an incorrect format

    Example:

        >>> check_addresses([('127.0.0.1', 22), ('127.0.0.1', 2222)])
    c                 s   s   | ]}t |ttfV  qd S N)r   r   r   .0xr   r   r   	<genexpr>   s     z"check_addresses.<locals>.<genexpr>c                 s   s   | ]}t |tV  qd S r*   )r   r   r+   r   r   r   r.      s     z3UNIX domain sockets not allowed for remoteaddressesN)allr   anyr)   )Zaddress_list	is_remoter(   r   r   r   check_addresses{   s
    r2   c                 C   s   | pt d} tdd | jD sJ| |p,t t  }t| ||pDtd |rn| | | jD ]}|| q^|r|t| d |rt	j
dkrt d t d}|j| j | S )	a  
    Attach or create a new logger and add a console handler if not present

    Arguments:

        logger (Optional[logging.Logger]):
            :class:`logging.Logger` instance; a new one is created if this
            argument is empty

        loglevel (Optional[str or int]):
            :class:`logging.Logger`'s level, either as a string (i.e.
            ``ERROR``) or in numeric format (10 == ``DEBUG``)

            .. note:: a value of 1 == ``TRACE`` enables Tracing mode

        capture_warnings (boolean):
            Enable/disable capturing the events logged by the warnings module
            into ``logger``'s handlers

            Default: True

            .. note:: ignored in python 2.6

        add_paramiko_handler (boolean):
            Whether or not add a console handler for ``paramiko.transport``'s
            logger if no handler present

            Default: True
    Return:
        :class:`logging.Logger`
    zsshtunnel.SSHTunnelForwarderc                 s   s   | ]}t |tjV  qd S r*   )r   loggingHandlerr+   r   r   r   r.      s     z create_logger.<locals>.<genexpr>)handlerloglevellogger)      Tzpy.warnings)r3   	getLoggerr0   handlerssetLevelDEFAULT_LOGLEVELStreamHandler_add_handler_check_paramiko_handlerssysversion_infocaptureWarningsextend)r8   r6   Zcapture_warningsZadd_paramiko_handlerconsole_handlerr5   Z
pywarningsr   r   r   create_logger   s*    #




rG   c                 C   sN   | |p
t |jtjkr0d}|t| n|td | | dS )z<
    Add a handler to an existing logging.Logger object
    z[%(asctime)s| %(levelname)-4.3s|%(threadName)10.9s/%(lineno)04d@%(module)-10.9s| %(message)sz)%(asctime)s| %(levelname)-8s| %(message)sN)r=   r>   levelr3   DEBUGsetFormatter	Formatter
addHandler)r8   r5   r6   _fmtr   r   r   r@      s    r@   c                 C   sD   t d}|js@| r| j|_n"t  }|t d || dS )zN
    Add a console handler for paramiko.transport's logger if not present
    zparamiko.transportzP%(asctime)s | %(levelname)-8s| PARAMIKO: %(lineno)03d@%(module)-10s| %(message)sN)r3   r;   r<   r?   rJ   rK   rL   )r8   Zparamiko_loggerrF   r   r   r   rA      s    

rA   c                 C   s   t | trd| S t| S )Nz{0[0]}:{0[1]})r   r   r   strr'   r   r   r   address_to_str   s    

rO   c               	   C   s    t  t} td7 aW 5 Q R X | S Nr   )_LOCK_CONNECTION_COUNTER)uidr   r   r   get_connection_id   s    rT   c                    s   t t j fdd D S )z, Remove dictionary keys whose value is None c                    s   g | ]} | d kr|qS r*   r   )r,   i
dictionaryr   r   
<listcomp>  s      z'_remove_none_values.<locals>.<listcomp>)listmappoprV   r   rV   r   _remove_none_values  s    r\   c                   @   s    e Zd ZdZdd Zdd ZdS )BaseSSHTunnelForwarderErrorz8 Exception raised by :class:`SSHTunnelForwarder` errors c                 O   s   | d|r|d nd| _d S )Nvaluer    )r[   r^   selfargskwargsr   r   r   __init__  s    z$BaseSSHTunnelForwarderError.__init__c                 C   s   | j S r*   )r^   ra   r   r   r   __str__  s    z#BaseSSHTunnelForwarderError.__str__N)r   
__module____qualname____doc__rd   rf   r   r   r   r   r]     s   r]   c                   @   s   e Zd ZdZdS )HandlerSSHTunnelForwarderErrorz' Exception for Tunnel forwarder errors N)r   rg   rh   ri   r   r   r   r   rj     s   rj   c                   @   s0   e Zd ZdZdZdZdZdZdd Zdd Z	dS )_ForwardHandlerz% Base handler for tunnel connections Nc              	   C   s   |j rt| j|gg g d\}}}| j|kr|| jd}|sR| jtd| j q| jtd| j| j	t
| || ||kr | s| jtd| j q|d}| jtd| jt
| | j| q d S )N   i   z>>> OUT {0} recv empty data >>>z >>> OUT {0} send to {1}: {2} >>>z <<< IN {0} recv is not ready <<<z<<< IN {0} recv: {1} <<<)activer   requestrecvr8   logTRACE_LEVELr   inforemote_addressr   sendallZ
recv_ready)ra   chanZrqst_datar   r   r   	_redirect1  s@    




z_ForwardHandler._redirectc                 C   s~  t  }d|| jp| jj| _| j }t|t	s6d}z| j
jd| j|td}W nf tk
r } zHt|tjrrdnd}d||}d| j|}| jt| t|W 5 d }~X Y nX | jtd	| j zz| | W nl tjk
r   | jtd| j Y n@ tk
rJ } z | jtd| jt| W 5 d }~X Y nX W 5 |  | j  | jtd
| j X d S )Nz#{0} <-- {1})dummyi90  zdirect-tcpip)kindZ	dest_addrZsrc_addrtimeoutzssh r_   zopen new channel {0}error: {1}z{0} {1}z{0} connectedz{0} connection closed.z{0} sending RSTz{0} error: {1})rT   r   client_addressserverlocal_addressrr   rn   getpeernamer   r   ssh_transportZopen_channelrs   TUNNEL_TIMEOUT	ExceptionparamikoSSHExceptionr8   rp   rq   rj   closerx   socketerrorrepr)ra   rS   Zsrc_addressru   eZmsg_tupeZexc_msgZlog_msgr   r   r   handleS  sD    




z_ForwardHandler.handle)
r   rg   rh   ri   rs   r   r8   rr   rx   r   r   r   r   r   rk   *  s   "rk   c                   @   sl   e Zd ZdZdZdd Zdd Zedd Zed	d
 Z	edd Z
edd Zedd Zedd ZdS )_ForwardServerz5
    Non-threading version of the forward server
    Tc                 O   s6   t |dd | _td| _tjj| f|| d S Nr8   r   )	rG   r[   r8   queueQueue	tunnel_oksocketserver	TCPServerrd   r`   r   r   r   rd     s    z_ForwardServer.__init__c                 C   s   t  \}}}| }| j}| jd||| z| jjdddd W n: t	j
k
r^   Y n& |k
r   | jd| Y nX d S )NzSCould not establish connection from local {0} to remote {1} side of the tunnel: {2}Fr   )blockr{   zunexpected internal error: {0})rB   exc_infogetsocknamers   r8   r   r   r   putr   Full)ra   rn   r|   	exc_classexctbZ
local_sideZremote_sider   r   r   handle_error  s    
  z_ForwardServer.handle_errorc                 C   s   | j S r*   server_addressre   r   r   r   r~     s    z_ForwardServer.local_addressc                 C   s
   | j d S Nr   r   re   r   r   r   
local_host  s    z_ForwardServer.local_hostc                 C   s
   | j d S rP   r   re   r   r   r   
local_port  s    z_ForwardServer.local_portc                 C   s   | j jS r*   RequestHandlerClassrs   re   r   r   r   rs     s    z_ForwardServer.remote_addressc                 C   s   | j jd S r   r   re   r   r   r   remote_host  s    z_ForwardServer.remote_hostc                 C   s   | j jd S rP   r   re   r   r   r   remote_port  s    z_ForwardServer.remote_portN)r   rg   rh   ri   allow_reuse_addressrd   r   propertyr~   r   r   rs   r   r   r   r   r   r   r   {  s    




r   c                   @   s   e Zd ZdZeZdS )_ThreadingForwardServer5
    Allow concurrent connections to each tunnel
    Nr   rg   rh   ri   _DAEMONdaemon_threadsr   r   r   r   r     s   r   c                   @   s`   e Zd ZdZdd Zedd Zedd Zedd	 Zed
d Z	edd Z
edd ZdS )_StreamForwardServerz>
    Serve over domain sockets (does not work on Windows)
    c                 O   s4   t |dd | _td| _tj| f|| d S r   )rG   r[   r8   r   r   r   _StreamServerrd   r`   r   r   r   rd     s    z_StreamForwardServer.__init__c                 C   s   | j S r*   r   re   r   r   r   r~     s    z"_StreamForwardServer.local_addressc                 C   s   d S r*   r   re   r   r   r   r     s    z_StreamForwardServer.local_hostc                 C   s   d S r*   r   re   r   r   r   r     s    z_StreamForwardServer.local_portc                 C   s   | j jS r*   r   re   r   r   r   rs     s    z#_StreamForwardServer.remote_addressc                 C   s   | j jd S r   r   re   r   r   r   r     s    z _StreamForwardServer.remote_hostc                 C   s   | j jd S rP   r   re   r   r   r   r     s    z _StreamForwardServer.remote_portN)r   rg   rh   ri   rd   r   r~   r   r   rs   r   r   r   r   r   r   r     s   




r   c                   @   s   e Zd ZdZeZdS )_ThreadingStreamForwardServerr   Nr   r   r   r   r   r     s   r   c                   @   s  e Zd ZdZdZeZeZdd Zdd Z	dd Z
d	d
 Zdd Zdd Zdd ZdeddddddddddddddddddfddZedWddZedXddZedYddZedd ZedZddZedfd d!Zd"d# Zd$d% Zed[d&d'Zed(d) Zed\d*d+Zd,d- Zd]d.d/Zd0d1 Z d2d3 Z!d4d5 Z"d^d7d8Z#d_d9d:Z$e%d;d< Z&e%d=d> Z'e%d?d@ Z(e%dAdB Z)e%dCdD Z*e%dEdF Z+e%dGdH Z,e%dIdJ Z-dKdL Z.dMdN Z/dOdP Z0dQdR Z1dSdT Z2dUdV Z3dS )`SSHTunnelForwardera	#  
    **SSH tunnel class**

        - Initialize a SSH tunnel to a remote host according to the input
          arguments

        - Optionally:
            + Read an SSH configuration file (typically ``~/.ssh/config``)
            + Load keys from a running SSH agent (i.e. Pageant, GNOME Keyring)

    Raises:

        :class:`.BaseSSHTunnelForwarderError`:
            raised by SSHTunnelForwarder class methods

        :class:`.HandlerSSHTunnelForwarderError`:
            raised by tunnel forwarder threads

            .. note::
                    Attributes ``mute_exceptions`` and
                    ``raise_exception_if_any_forwarder_have_a_problem``
                    (deprecated) may be used to silence most exceptions raised
                    from this class

    Keyword Arguments:

        ssh_address_or_host (tuple or str):
            IP or hostname of ``REMOTE GATEWAY``. It may be a two-element
            tuple (``str``, ``int``) representing IP and port respectively,
            or a ``str`` representing the IP address only

            .. versionadded:: 0.0.4

        ssh_config_file (str):
            SSH configuration file that will be read. If explicitly set to
            ``None``, parsing of this configuration is omitted

            Default: :const:`SSH_CONFIG_FILE`

            .. versionadded:: 0.0.4

        ssh_host_key (str):
            Representation of a line in an OpenSSH-style "known hosts"
            file.

            ``REMOTE GATEWAY``'s key fingerprint will be compared to this
            host key in order to prevent against SSH server spoofing.
            Important when using passwords in order not to accidentally
            do a login attempt to a wrong (perhaps an attacker's) machine

        ssh_username (str):
            Username to authenticate as in ``REMOTE SERVER``

            Default: current local user name

        ssh_password (str):
            Text representing the password used to connect to ``REMOTE
            SERVER`` or for unlocking a private key.

            .. note::
                Avoid coding secret password directly in the code, since this
                may be visible and make your service vulnerable to attacks

        ssh_port (int):
            Optional port number of the SSH service on ``REMOTE GATEWAY``,
            when `ssh_address_or_host`` is a ``str`` representing the
            IP part of ``REMOTE GATEWAY``'s address

            Default: 22

        ssh_pkey (str or paramiko.PKey):
            **Private** key file name (``str``) to obtain the public key
            from or a **public** key (:class:`paramiko.pkey.PKey`)

        ssh_private_key_password (str):
            Password for an encrypted ``ssh_pkey``

            .. note::
                Avoid coding secret password directly in the code, since this
                may be visible and make your service vulnerable to attacks

        ssh_proxy (socket-like object or tuple):
            Proxy where all SSH traffic will be passed through.
            It might be for example a :class:`paramiko.proxy.ProxyCommand`
            instance.
            See either the :class:`paramiko.transport.Transport`'s sock
            parameter documentation or ``ProxyCommand`` in ``ssh_config(5)``
            for more information.

            It is also possible to specify the proxy address as a tuple of
            type (``str``, ``int``) representing proxy's IP and port

            .. note::
                Ignored if ``ssh_proxy_enabled`` is False

            .. versionadded:: 0.0.5

        ssh_proxy_enabled (boolean):
            Enable/disable SSH proxy. If True and user's
            ``ssh_config_file`` contains a ``ProxyCommand`` directive
            that matches the specified ``ssh_address_or_host``,
            a :class:`paramiko.proxy.ProxyCommand` object will be created where
            all SSH traffic will be passed through

            Default: ``True``

            .. versionadded:: 0.0.4

        local_bind_address (tuple):
            Local tuple in the format (``str``, ``int``) representing the
            IP and port of the local side of the tunnel. Both elements in
            the tuple are optional so both ``('', 8000)`` and
            ``('10.0.0.1', )`` are valid values

            Default: ``('0.0.0.0', RANDOM_PORT)``

            .. versionchanged:: 0.0.8
                Added the ability to use a UNIX domain socket as local bind
                address

        local_bind_addresses (list[tuple]):
            In case more than one tunnel is established at once, a list
            of tuples (in the same format as ``local_bind_address``)
            can be specified, such as [(ip1, port_1), (ip_2, port2), ...]

            Default: ``[local_bind_address]``

            .. versionadded:: 0.0.4

        remote_bind_address (tuple):
            Remote tuple in the format (``str``, ``int``) representing the
            IP and port of the remote side of the tunnel.

        remote_bind_addresses (list[tuple]):
            In case more than one tunnel is established at once, a list
            of tuples (in the same format as ``remote_bind_address``)
            can be specified, such as [(ip1, port_1), (ip_2, port2), ...]

            Default: ``[remote_bind_address]``

            .. versionadded:: 0.0.4

        allow_agent (boolean):
            Enable/disable load of keys from an SSH agent

            Default: ``True``

            .. versionadded:: 0.0.8

        host_pkey_directories (list):
            Look for pkeys in folders on this list, for example ['~/.ssh'].

            Default: ``None`` (disabled)

            .. versionadded:: 0.1.4

        compression (boolean):
            Turn on/off transport compression. By default compression is
            disabled since it may negatively affect interactive sessions

            Default: ``False``

            .. versionadded:: 0.0.8

        logger (logging.Logger):
            logging instance for sshtunnel and paramiko

            Default: :class:`logging.Logger` instance with a single
            :class:`logging.StreamHandler` handler and
            :const:`DEFAULT_LOGLEVEL` level

            .. versionadded:: 0.0.3

        mute_exceptions (boolean):
            Allow silencing :class:`BaseSSHTunnelForwarderError` or
            :class:`HandlerSSHTunnelForwarderError` exceptions when enabled

            Default: ``False``

            .. versionadded:: 0.0.8

        set_keepalive (float):
            Interval in seconds defining the period in which, if no data
            was sent over the connection, a *'keepalive'* packet will be
            sent (and ignored by the remote host). This can be useful to
            keep connections alive over a NAT. You can set to 0.0 for
            disable keepalive.

            Default: 5.0 (no keepalive packets are sent)

            .. versionadded:: 0.0.7

        threaded (boolean):
            Allow concurrent connections over a single tunnel

            Default: ``True``

            .. versionadded:: 0.0.3

        ssh_address (str):
            Superseded by ``ssh_address_or_host``, tuple of type (str, int)
            representing the IP and port of ``REMOTE SERVER``

            .. deprecated:: 0.0.4

        ssh_host (str):
            Superseded by ``ssh_address_or_host``, tuple of type
            (str, int) representing the IP and port of ``REMOTE SERVER``

            .. deprecated:: 0.0.4

        ssh_private_key (str or paramiko.PKey):
            Superseded by ``ssh_pkey``, which can represent either a
            **private** key file name (``str``) or a **public** key
            (:class:`paramiko.pkey.PKey`)

            .. deprecated:: 0.0.8

        raise_exception_if_any_forwarder_have_a_problem (boolean):
            Allow silencing :class:`BaseSSHTunnelForwarderError` or
            :class:`HandlerSSHTunnelForwarderError` exceptions when set to
            False

            Default: ``True``

            .. versionadded:: 0.0.4

            .. deprecated:: 0.0.8 (use ``mute_exceptions`` instead)

    Attributes:

        tunnel_is_up (dict):
            Describe whether or not the other side of the tunnel was reported
            to be up (and we must close it) or not (skip shutting down that
            tunnel)

            .. note::
                This attribute should not be modified

            .. note::
                When :attr:`.skip_tunnel_checkup` is disabled or the local bind
                is a UNIX socket, the value will always be ``True``

            **Example**::

                {('127.0.0.1', 55550): True,   # this tunnel is up
                 ('127.0.0.1', 55551): False}  # this one isn't

            where 55550 and 55551 are the local bind ports

        skip_tunnel_checkup (boolean):
            Disable tunnel checkup (default for backwards compatibility).

            .. versionadded:: 0.1.0

    Tc                 C   sF   zt | W n" tk
r.   | jd Y dS X |   | j|dS )a  
        Check if a tunnel is up (remote target's host is reachable on TCP
        target's port)

        Arguments:
            target (tuple):
                tuple of type (``str``, ``int``) indicating the listen IP
                address and port
        Return:
            boolean

        .. deprecated:: 0.1.0
            Replaced by :meth:`.check_tunnels()` and :attr:`.tunnel_is_up`
        zTarget must be a tuple (IP, port), where IP is a string (i.e. "192.168.0.1") and port is an integer (i.e. 40000). Alternatively target can be a valid UNIX domain socket.FT)r)   r!   r8   warningcheck_tunnelstunnel_is_upget)ra   targetr   r   r   local_is_up  s    zSSHTunnelForwarder.local_is_upc                 C   s4   | j }z d| _ | jD ]}| | qW 5 || _ X dS )zg
        Check that if all tunnels are established and populates
        :attr:`.tunnel_is_up`
        FN)skip_tunnel_checkup_server_list_check_tunnel)ra   r   _srvr   r   r   r     s    
z SSHTunnelForwarder.check_tunnelsc                 C   s:  | j rd| j|j< dS | jd|j t|jtrHt		t	j
t	j}nt		t	jt	j}|t zzV|jdkrzd|jfn|j}|| |jjtd d| j|j< | jd|j W nl t	jk
r   | jd|j d	| j|j< Y n8 tjk
r&   | jd
|j d| j|j< Y nX W 5 |  X dS )z( Check if tunnel is already established TNzChecking tunnel to: {0}0.0.0.0z	127.0.0.1g?)r{   zTunnel to {0} is DOWNFzTunnel to {0} is UP)r   r   r~   r8   rr   r   rs   r   r   r   AF_UNIXSOCK_STREAMAF_INET
settimeoutr   r   r   r   connectr   r   debugr   r   Empty)ra   r   sZ
connect_tor   r   r   r     s>    




z SSHTunnelForwarder._check_tunnelc                    s   G  fdddt }|S )z(
        Make SSH Handler class
        c                       s   e Zd Z ZjZjZdS )zCSSHTunnelForwarder._make_ssh_forward_handler_class.<locals>.HandlerN)r   rg   rh   rs   
_transportr   r8   r   remote_address_ra   r   r   r4   <  s   r4   )rk   )ra   r   r4   r   r   r   _make_ssh_forward_handler_class8  s    z2SSHTunnelForwarder._make_ssh_forward_handler_classc                 C   s   | j r
tS tS r*   )	_threadedr   r   ra   r   r   r   r   _make_ssh_forward_server_classB  s    z1SSHTunnelForwarder._make_ssh_forward_server_classc                 C   s   | j r
tS tS r*   )r   r   r   r   r   r   r   %_make_stream_ssh_forward_server_classE  s    
z8SSHTunnelForwarder._make_stream_ssh_forward_server_classc                 C   s   |  |}ztt|tr| jn| j}||}|||| jd}|r`| j|_| j	| d| j
|j< n| tdt|t| W n0 tk
r   | tdt|t| Y nX dS )z5
        Make SSH forward proxy Server class
        r7   FzsProblem setting up ssh {0} <> {1} forwarder. You can suppress this exception by using the `mute_exceptions`argumentzLCouldn't open tunnel {0} <> {1} might be in use or destination not reachableN)r   r   r   r   r   r8   daemon_forward_serversr   r   appendr   r   _raiser]   r   rO   IOError)ra   rs   local_bind_addressZ_HandlerZforward_maker_classZ_ServerZssh_forward_serverr   r   r   _make_ssh_forward_serverI  s>    
z+SSHTunnelForwarder._make_ssh_forward_serverNFg      @c              
   O   s  |pt  | _t|d || _|| _g | _i | _|| _d| _dD ]}| 	|||}q>| 	|d|}| 	d d|pr| | _
t|trt| |\}}n|}|dd }|rtd|| j||dd	| _| |
|| _| | j| j| _| |||	|||r|nd || j\| _| _}| _| _| _| j|||||| jd
\| _| _t| j t| j | j d| j| j| j | j!d| j d S )Nr7   Fr
   r   r   r   ssh_portzUnknown arguments: {0}T)r1   )ssh_passwordr   ssh_pkey_passwordallow_agenthost_pkey_directoriesr8   z,Connecting to gateway: {0}:{1} as user '{2}'z#Concurrent connections allowed: {0})"rG   r8   rA   ssh_host_keyset_keepaliver   r   r   is_alive_process_deprecated_raise_fwd_excr   r   r)   r[   r!   r   
_get_binds_remote_binds_local_binds_consolidate_binds_read_ssh_configr   ssh_usernamer   	ssh_proxycompression_consolidate_authr   	ssh_pkeysr   r   rr   r   )ra   r   ssh_config_filer   r   r   ssh_private_key_passwordr   Zssh_proxy_enabledr   r   local_bind_addressesr8   r	   Zremote_bind_addressremote_bind_addressesr   Zthreadedr   r   r   rb   rc   deprecated_argumentr   r   r   r   r   rd   o  s    



	



zSSHTunnelForwarder.__init__c                 C   sX  t  }|sd}dzzttj|d}	|	|	 W 5 Q R X |
| }
|pV|
d}|pl|
ddgd }|
d} |p|
d}|
d	}|p|rt |nd}|dkr|
d
d}| dkrdnd}W nP tk
r   |r|d| Y n* ttfk
r    |r|d Y nX W 5 | |p4t ||rDt|nd||f  S X  )z
        Read ssh_config_file and tries to look for user (ssh_username),
        identityfile (ssh_pkey), port (ssh_port) and proxycommand
        (ssh_proxy) entries for ssh_host
        N   ruserZidentityfiler   hostnamer   proxycommandr   r_   ZYESTFz*Could not read SSH configuration file: {0}z*Skipping loading of ssh configuration file)r   Z	SSHConfiggetpassgetuserr   openr   r"   
expanduserparselookupr   ProxyCommandupperr   r   r   AttributeError	TypeErrorrr   )r   r   r   r   r   r   r   r8   Z
ssh_configfZhostname_infor   r   r   r   r     sR    


z#SSHTunnelForwarder._read_ssh_configc                 C   s0   t  }| }| r(| dt| t|S )z Load public keys from any available SSH agent

        Arguments:
            logger (Optional[logging.Logger])

        Return:
            list
        z{0} keys loaded from agent)r   ZAgentget_keysrr   r   lenrY   )r8   Zparamiko_agentZ
agent_keysr   r   r   get_agent_keys  s
    
z!SSHTunnelForwarder.get_agent_keysc           
      C   s  |rt j| dng }|dkr"tg}tjtjtjd}ttdrHtj|d< |D ]}|	 D ]}t
jt
j|d|}z2t
j|rt j|| || d}|r|| W qX tk
r }	 z| r| d||	 W 5 d}	~	X Y qXX qXqL| r| d	t| |S )
a3  
        Load public keys from any available SSH agent or local
        .ssh directory.

        Arguments:
            logger (Optional[logging.Logger])

            host_pkey_directories (Optional[list[str]]):
                List of local directories where host SSH pkeys in the format
                "id_*" are searched. For example, ['~/.ssh']

                .. versionadded:: 0.1.0

            allow_agent (Optional[boolean]):
                Whether or not load keys from agent

                Default: False

        Return:
            list
        r7   N)rsaZdsaZecdsa
Ed25519KeyZed25519zid_{})	pkey_filer8   key_typez%Private key file {0} check error: {1}z{0} key(s) loaded)r   r   DEFAULT_SSH_DIRECTORYr   RSAKeyDSSKeyECDSAKeyhasattrr   keysr   r"   r   joinr   isfileread_private_key_filer   OSErrorr   rr   r   )
r8   r   r   r  Zparamiko_key_types	directoryZkeytypessh_pkey_expandedr   r   r   r   r   r   '  sF    

 zSSHTunnelForwarder.get_keysc                 C   s<   t |t |  }|dk r td| dd t|D  | S )z
        Fill local_binds with defaults when no value/s were specified,
        leaving paramiko to decide in which local port the tunnel will be open
        r   zLToo many local bind addresses (local_bind_addresses > remote_bind_addresses)c                 S   s   g | ]}d qS ))r   r   r   r+   r   r   r   rX   j  s     z9SSHTunnelForwarder._consolidate_binds.<locals>.<listcomp>)r   r!   rE   range)Zlocal_bindsZremote_bindscountr   r   r   r   `  s
    z%SSHTunnelForwarder._consolidate_bindsc                 C   s   t j|||d}t|tr\tj|}tj|rHt j||p>| |d}n|r\|	d
| t|tjjrv|d| | s|std| |fS )a2  
        Get sure authentication information is in place.
        ``ssh_pkey`` may be of classes:
            - ``str`` - in this case it represents a private key file; public
            key will be obtained from it
            - ``paramiko.Pkey`` - it will be transparently added to loaded keys

        )r8   r   r   )r   pkey_passwordr8   zPrivate key file not found: {0}r   z$No password or public key available!)r   r   r   r   r   r"   r   r#   r	  r   r   r   pkeyZPKeyinsertr!   )r   r   r   r   r   r8   Zssh_loaded_pkeysr  r   r   r   r   m  s,    
z$SSHTunnelForwarder._consolidate_authc                 C   s(   | j r||n| jt|| d S r*   )r   r8   r   r   )ra   	exceptionreasonr   r   r   r     s    
zSSHTunnelForwarder._raisec                 C   s
  | j rLt| j tjjr(t| j jd }n
t| j }| jd	| | j }n| j
| jf}t|tjr|t || j
| jf t|}|j}t|tjr|t || j |j| jd | j|_t|tjr| }t|j|j|jf}| jd	|| |S )z0 Return the SSH transport to the remote gateway r   zConnecting via proxy: {0})compressz'Transport socket info: {0}, timeout={1})r   r   r   proxyr   r   cmdr8   r   r   r   r   r   r   SSH_TIMEOUTr   	Transportsockr   Zuse_compressionr   daemon_transportdaemon
gettimeoutfamilyr   proto)ra   Z
proxy_repr_socket	transportr  Zsock_timeoutZ	sock_infor   r   r   _get_transport  s2    




 z!SSHTunnelForwarder._get_transportc                 C   s  | j sz|   W n tjk
rB   d| j}| j| Y dS  tj	tjfk
r } z2d}|| j| j
|jd }| j| W Y dS d}~X Y nX t| j| jD ]V\}}z| || W q tk
 r } zd|j}| j| W 5 d}~X Y qX qdS )zP
        Create SSH tunnels on top of a transport to the remote gateway
        z/Could not resolve IP address for {0}, aborting!Nz*Could not connect to gateway {0}:{1} : {2}r   z%Problem setting SSH Forwarder up: {0})	is_active_connect_to_gatewayr   gaierrorr   r   r8   r   r   r   r   rb   zipr   r   r   r]   r^   )ra   msgr   templateremlocr   r   r   _create_tunnels  s(    z"SSHTunnelForwarder._create_tunnelsc                 C   s   |rdnd}| s.|s.|r(t d|qDg S n| rD|rDt d|| rN| g}|st|D ].\}}t|trZt|dkrZ|d df||< qZt|| |S )NremotelocalzXNo {0} bind addresses specified. Use '{0}_bind_address' or '{0}_bind_addresses' argumentzZYou can't use both '{0}_bind_address' and '{0}_bind_addresses' arguments. Use one of them.r   r   )r!   r   	enumerater   r   r   r2   )Zbind_addressZbind_addressesr1   Z	addr_kindrU   Z
local_bindr   r   r   r     s&    
zSSHTunnelForwarder._get_bindsc                 C   s^   |t krtd|||krZtd|t | t | rPtd|t | n
||S | S )z8
        Processes optional deprecate arguments
        z%{0} not included in deprecations listz%'{0}' is DEPRECATED use '{1}' insteadz?You can't use both '{0}' and '{1}'. Please only use one of them)_DEPRECATIONSr!   r   warningswarnDeprecationWarningr[   )ZattribZdeprecated_attribrc   r   r   r   r     s$    
z&SSHTunnelForwarder._process_deprecatedc              
   C   s   d}t jt jt jf}tt dr*|t jf7 }|r4|fn|D ]}z.|j| |d}|rb|d| | W  qW q8 t j	k
r   |r|
d|  Y  qY q8 t jk
r   |r|d| | Y q8X q8|S )a  
        Get SSH Public key from a private key file, given an optional password

        Arguments:
            pkey_file (str):
                File containing a private key (RSA, DSS or ECDSA)
        Keyword Arguments:
            pkey_password (Optional[str]):
                Password to decrypt the private key
            logger (Optional[logging.Logger])
        Return:
            paramiko.Pkey
        Nr   )passwordz/Private key file ({0}, {1}) successfully loadedz Password is required for key {0}zFPrivate key file ({0}) could not be loaded as type {1} or bad password)r   r  r  r  r  r   Zfrom_private_key_filer   r   ZPasswordRequiredExceptionr   r   )r   r  r   r8   r   Z	key_typesZ
pkey_classr   r   r   r	    s:    
 

 z(SSHTunnelForwarder.read_private_key_filec                 C   s   | j r| jd dS |   | js2| jtdd | jD ]>}tj	| j
|fdt|jd}| j|_|  | | q8t| j | _ | j s| td dS )z Start the SSH tunnels zAlready started!Nz*Could not establish session to SSH gateway)r  zSrv-{0})r   rb   r    z(An error occurred while opening tunnels.)r   r8   r   r*  r"  r   r]   r   	threadingThread_serve_forever_wrapperr   rO   r   r   r  startr   r0   r   valuesrj   )ra   r   threadr   r   r   r6  ,  s,    
zSSHTunnelForwarder.startc                 C   sR   | j d ddd | jD p$d}| j d|  | j|d g | _i | _dS )	a  
        Shut the tunnel down. By default we are always waiting until closing
        all connections. You can use `force=True` to force close connections

        Keyword Arguments:
            force (bool):
                Force close current connections

                Default: False

                .. versionadded:: 0.2.2

        .. note:: This **had** to be handled with care before ``0.1.0``:

            - if a port redirection is opened
            - the destination is not reachable
            - we attempt a connection to that tunnel (``SYN`` is sent and
              acknowledged, then a ``FIN`` packet is sent and never
              acknowledged... weird)
            - we try to shutdown: it will not succeed until ``FIN_WAIT_2`` and
              ``CLOSE_WAIT`` time out.

        .. note::
            Handle these scenarios with :attr:`.tunnel_is_up`: if False, server
            ``shutdown()`` will be skipped on that tunnel
        zClosing all open connections...z, c                 s   s   | ]}t |jV  qd S r*   )rO   r~   )r,   kr   r   r   r.   `  s     z*SSHTunnelForwarder.stop.<locals>.<genexpr>NonezListening tunnels: forceN)r8   rr   r  r   r   _stop_transportr   )ra   r<  Zopened_address_textr   r   r   stopC  s    zSSHTunnelForwarder.stopc                 C   s   |    dS )z3 Stop the an active tunnel, alias to :meth:`.stop` Nr>  re   r   r   r   r   g  s    zSSHTunnelForwarder.closec                 C   s   |    |   dS )z/ Restart connection to the gateway and tunnels N)r>  r6  re   r   r   r   restartk  s    zSSHTunnelForwarder.restartc              	   C   s  | j D ]~}| jdt|  z4|  | _| jj| j	| j
|d | jjrVW  dS W q tjk
r   | jd |   Y qX q| jr| jddt| j  z4|  | _| jj| j	| j
| jd | jjrW dS W n, tjk
r
   | jd |   Y nX | jd dS )	z
        Open connection to SSH gateway
         - First try with all keys loaded from an SSH agent (if allowed)
         - Then with those passed directly or read from ~/.ssh/config
         - As last resort, try with a provided password
        zTrying to log in with key: {0})hostkeyusernamer  NzAuthentication errorz#Trying to log in with password: {0}*)rA  rB  r2  z$Could not open connection to gateway)r   r8   r   r   r   get_fingerprintr!  r   r   r   r   r   r   ZAuthenticationExceptionr=  r   r   r   )ra   keyr   r   r   r#  p  s>    








z&SSHTunnelForwarder._connect_to_gatewayr   c                 C   sN   | j dt|jt|j || | j dt|jt|j dS )zB
        Wrapper for the server created for a SSH forward
        zOpening tunnel: {0} <> {1}zTunnel: {0} <> {1} releasedN)r8   rr   r   rO   r~   rs   serve_forever)ra   r   poll_intervalr   r   r   r5    s    


z)SSHTunnelForwarder._serve_forever_wrapperc                 C   sT  z|    W n2 ttfk
r> } z| j| W 5 d}~X Y nX |rj| jrj| jd | j  | j	  | j
D ]}| j|j rdnd}| jdt|jt|j| |  |  t|trpzt|j W qp tk
r } z| jd|jt| W 5 d}~X Y qpX qpd| _| jrD| jd | j  | j	  | jd dS )	z< Close the underlying transport when nothing more is needed NzClosing ssh transportupZdownz&Shutting down tunnel: {0} <> {1} ({2})z Unable to unlink socket {0}: {1}FzTransport is closed)_check_is_startedr]   rj   r8   r   r"  rr   r   r   Zstop_threadr   r   r~   r   rO   rs   shutdownserver_closer   r   r   unlinkr   r   r   r   r   )ra   r<  r   r   statusr   r   r   r=    sB    






 

z"SSHTunnelForwarder._stop_transportc                 C   s(   |    t| jdkrtd| jd S )Nr   z7Use .local_bind_ports property for more than one tunnelr   )rI  r   r   r]   local_bind_portsre   r   r   r   local_bind_port  s    z"SSHTunnelForwarder.local_bind_portc                 C   s(   |    t| jdkrtd| jd S )Nr   z7Use .local_bind_hosts property for more than one tunnelr   )rI  r   r   r]   local_bind_hostsre   r   r   r   local_bind_host  s    z"SSHTunnelForwarder.local_bind_hostc                 C   s(   |    t| jdkrtd| jd S )Nr   z;Use .local_bind_addresses property for more than one tunnelr   )rI  r   r   r]   r   re   r   r   r   r     s    z%SSHTunnelForwarder.local_bind_addressc                 C   s   |    dd | jD S )zU
        Return a list containing the ports of local side of the TCP tunnels
        c                 S   s   g | ]}|j d k	r|j qS r*   )r   r,   _serverr   r   r   rX     s    
z7SSHTunnelForwarder.local_bind_ports.<locals>.<listcomp>rI  r   re   r   r   r   rN    s    z#SSHTunnelForwarder.local_bind_portsc                 C   s   |    dd | jD S )zU
        Return a list containing the IP addresses listening for the tunnels
        c                 S   s   g | ]}|j d k	r|j qS r*   )r   rR  r   r   r   rX     s    
z7SSHTunnelForwarder.local_bind_hosts.<locals>.<listcomp>rT  re   r   r   r   rP    s    z#SSHTunnelForwarder.local_bind_hostsc                 C   s   |    dd | jD S )zU
        Return a list of (IP, port) pairs for the local side of the tunnels
        c                 S   s   g | ]
}|j qS r   )r~   rR  r   r   r   rX     s     z;SSHTunnelForwarder.local_bind_addresses.<locals>.<listcomp>rT  re   r   r   r   r     s    z'SSHTunnelForwarder.local_bind_addressesc                    s   t  fdd jD S )zY
        Return a dictionary containing the active local<>remote tunnel_bindings
        c                 3   s&   | ]} j |j r|j|jfV  qd S r*   )r   r~   rs   rR  re   r   r   r.     s   z5SSHTunnelForwarder.tunnel_bindings.<locals>.<genexpr>)dictr   re   r   re   r   tunnel_bindings  s    z"SSHTunnelForwarder.tunnel_bindingsc                 C   s   d| j kr| j rdS dS )z3 Return True if the underlying SSH transport is up r   TF)__dict__r   r"  re   r   r   r   r"    s    zSSHTunnelForwarder.is_activec                 C   s(   | j sd}t|| js$d}t|d S )Nz-Server is not started. Please .start() first!z/Tunnels are not started. Please .start() first!)r"  r]   r   rj   )ra   r&  r   r   r   rI    s    z$SSHTunnelForwarder._check_is_startedc                 C   s   | j t| jrdd | jD nd d}t| tjdddddd	d
dddddddg}|| j| j	| j
| jrx| jjd nd| j|| jr| jnd| jrdnd| jsdn
d| j| jrdnd| jrdnd| jrdndt| jj| j| jS )Nc                 S   s    g | ]}|  t| fqS r   )get_namer   rD  )r,   rE  r   r   r   rX     s   z.SSHTunnelForwarder.__str__.<locals>.<listcomp>)r2  Zpkeysz
{0} objectzssh gateway: {1}:{2}z
proxy: {3}zusername: {4}zauthentication: {5}zhostkey: {6}zstatus: {7}startedzkeepalive messages: {8}ztunnel connection check: {9}z#concurrent connections: {10}allowedzcompression: {11}requestedzlogging level: {12}zlocal binds: {13}zremote binds: {14}r   noznot checkedr_   znot disabledzevery {0} secenabled)r   r0   r   r\   r   linesepr  r   	__class__r   r   r   r  r   r   r   r   r   r   r   r3   getLevelNamer8   rH   r   r   )ra   credentialsr'  r   r   r   rf     sR    

zSSHTunnelForwarder.__str__c                 C   s   |   S r*   )rf   re   r   r   r   __repr__C  s    zSSHTunnelForwarder.__repr__c                 C   s0   z|    | W S  tk
r*   |   Y nX d S r*   )r6  KeyboardInterrupt__exit__re   r   r   r   	__enter__F  s
    zSSHTunnelForwarder.__enter__c                 G   s   | j dd d S )NTr;  r?  )ra   rb   r   r   r   rb  M  s    zSSHTunnelForwarder.__exit__c                 C   s(   | j s| jr$| jd | jdd d S )NzIt looks like you didn't call the .stop() before the SSHTunnelForwarder obj was collected by the garbage collector! Running .stop(force=True)Tr;  )r"  r   r8   r   r>  re   r   r   r   __del__P  s
    zSSHTunnelForwarder.__del__)NNNNNN)N)NNF)NNNTNN)F)NNN)F)r   )F)4r   rg   rh   ri   r   r   r   r  r   r   r   r   r   r   r   SSH_CONFIG_FILErd   staticmethodr   r   r   r   r   r]   r   r!  r*  r   r   r	  r6  r>  r   r@  r#  r5  r=  r   rO  rQ  r   rN  rP  r   rV  r"  rI  rf   r`  rc  rb  rd  r   r   r   r   r     s     $
(
k      <8
      &
   ,
$%

#
	
	
	




	)r   c                  O   s   t |dd|ddd|d< |dd}dD ]}t|||}q0|dd}|d	d
}|dd}|rxtdt | st|t	r|f} n
||ff} t| |}||_
|S )a  
    Open an SSH Tunnel, wrapper for :class:`SSHTunnelForwarder`

    Arguments:
        destination (Optional[tuple]):
            SSH server's IP address and port in the format
            (``ssh_address``, ``ssh_port``)

    Keyword Arguments:
        debug_level (Optional[int or str]):
            log level for :class:`logging.Logger` instance, i.e. ``DEBUG``

        skip_tunnel_checkup (boolean):
            Enable/disable the local side check and populate
            :attr:`~SSHTunnelForwarder.tunnel_is_up`

            Default: True

            .. versionadded:: 0.1.0

    .. note::
        A value of ``debug_level`` set to 1 == ``TRACE`` enables tracing mode
    .. note::
        See :class:`SSHTunnelForwarder` for keyword arguments

    **Example**::

        from sshtunnel import open_tunnel

        with open_tunnel(SERVER,
                         ssh_username=SSH_USER,
                         ssh_port=22,
                         ssh_password=SSH_PASSWORD,
                         remote_bind_address=(REMOTE_HOST, REMOTE_PORT),
                         local_bind_address=('', LOCAL_PORT)) as server:
            def do_something(port):
                pass

            print("LOCAL PORTS:", server.local_bind_port)

            do_something(server.local_bind_port)
    r8   Ndebug_level)r8   r6   r   r   r   r   r   Tblock_on_closez'block_on_close' is DEPRECATED. You should use either .stop() or .stop(force=True), depends on what you do with the active connections. This option has no affect since 0.3.0)rG   r   r[   r   r   r/  r0  r1  r   r   r   )rb   rc   r   r   r   r   rh  Z	forwarderr   r   r   open_tunnelY  s0    ,




ri  c                 C   s   zP|  d}t|dkr&|d }d}n|\}}|s<|s<tn|sDd}|t|fW S  tk
rn   tdY n tk
r   tdY nX dS )z Define type of data expected for remote and local bind address lists
        Returns a tuple (ip_address, port) whose elements are (str, int)
    :r   r   NZ22z-Address tuple must be of type IP_ADDRESS:PORTzBoth IP:PORT can't be missing!)splitr   r   r   r!   argparseArgumentTypeError)Z	input_strZip_port_ipZ_portr   r   r   	_bindlist  s"    
ro  c                 C   s  t jdtt jd}|jdtdd |jddtdd	d
 |jddtdddd |jddtddd
 |jddtdg ddddd	 |jddtdd dd!d" |jd#d$td%d |jd&d'd(d)td*d+ |jd,d-d.d/td0d+ |jd1d2d3d4d5 |jd6d7d8d9d:t	
td; |jd<d=d>d?jtd@dAdB |jdCdDtdEddFdG |jdHdIttdJdKtdL |jdMdNd3dOdPdQ |jdRdSdTdUdVdQ |jdWdXddYdZd[d\ t|| S )]z2
    Parse arguments directly passed from CLI
    z(Pure python ssh tunnel utils
Version {0})descriptionformatter_classr
   zbSSH server IP address (GW for SSH tunnels)
set with "-- ssh_address" if immediately after -R or -L)r   helpz-Uz
--usernamer   zSSH server account username)r   destrr  z-pz--server_portr   r   z!SSH server TCP port (default: 22))r   rs  defaultrr  z-Pz
--passwordr   zSSH server account passwordz-Rz--remote_bind_address+zIP:PORTTr   zRemote bind address sequence: ip_1:port_1 ip_2:port_2 ... ip_n:port_n
Equivalent to ssh -Lxxxx:IP_ADDRESS:PORT
If port is omitted, defaults to 22.
Example: -R 10.10.10.10: 10.10.10.10:5900)r   nargsrt  metavarrequiredrs  rr  z-Lz--local_bind_addressrC  r   aT  Local bind address sequence: ip_1:port_1 ip_2:port_2 ... ip_n:port_n
Elements may also be valid UNIX socket domains: 
/tmp/foo.sock /tmp/bar.sock ... /tmp/baz.sock
Equivalent to ssh -LPORT:xxxxxxxxx:xxxx, being the local IP address optional.
By default it will listen in all interfaces (0.0.0.0) and choose a random port.
Example: -L :40000)r   rv  rs  rw  rr  z-kz--ssh_host_keyzGateway's host keyz-Kz--private_key_filer   ZKEY_FILEzRSA/DSS/ECDSA private key file)rs  rw  r   rr  z-Sz--private_key_passwordr   ZKEY_PASSWORDz"RSA/DSS/ECDSA private key passwordz-tz
--threaded
store_truez+Allow concurrent connections to each tunnel)actionrr  z-vz	--verboser  r   z(Increase output verbosity (default: {0}))rz  rt  rr  z-Vz	--versionversionz%(prog)s {version})r{  zShow version number and quit)rz  r{  rr  z-xz--proxyr   z'IP and port of SSH proxy to destination)r   rs  rw  rr  z-cz--configr   z'SSH configuration file, defaults to {0})r   rt  rs  rr  z-zz
--compressr   z1Request server for compression over SSH transport)rz  rs  rr  z-nz	--noagentstore_falser   z*Disable looking for keys from an SSH agentz-dz--host_pkey_directoriesr   ZFOLDERzGList of directories where SSH pkeys (in the format `id_*`) may be found)rv  rs  rw  rr  )rl  ArgumentParserr   __version__RawTextHelpFormatteradd_argumentrN   r   ro  r3   r^  r>   re  vars
parse_args)rb   parserr   r   r   _parse_arguments  s             	 
     r  c              	   K   s   t | }t| t|dd}tjtjtjtjt	g}|
d||  | D ]\}}|
|| qNtf |}|jr~td W 5 Q R X dS )a   Pass input arguments to open_tunnel

        Mandatory: ssh_address, -R (remote bind address list)

        Optional:
        -U (username) we may gather it from SSH_CONFIG_FILE or current username
        -p (server_port), defaults to 22
        -P (password)
        -L (local_bind_address), default to 0.0.0.0:22
        -k (ssh_host_key)
        -K (private_key_file), may be gathered from SSH_CONFIG_FILE
        -S (private_key_password)
        -t (threaded), allow concurrent connections over tunnels
        -v (verbose), up to 3 (-vvv) to raise loglevel from ERROR to DEBUG
        -V (version)
        -x (proxy), ProxyCommand's IP:PORT, may be gathered from config file
        -c (ssh_config), ssh configuration file (defaults to SSH_CONFIG_FILE)
        -z (compress)
        -n (noagent), disable looking for keys from an Agent
        -d (host_pkey_directories), look for keys on these folders
    verbose   rg  z>

            Press <Ctrl-C> or <Enter> to stop!

            N)r  r\   minr[   r3   ERRORWARNINGINFOrI   rq   
setdefaultitemsri  r   input_)rb   extras	arguments	verbosityZlevelsextrar^   Ztunnelr   r   r   	_cli_mainY  s    r  __main__)F)NNTT)NN)N)N)N)Hri   r   rB   r   r   r3   rl  r/  r3  r   binasciir   r   rC   r   r   SocketServerr   
basestringr   	raw_inputr  rN   inputr~  
__author__r  r   r   rR   LockrQ   r.  r  r>   rq   addLevelNamer  r    UnixStreamServerr   r   r"   r  re  r   r   r)   r2   rG   r@   rA   rO   rT   r\   r   r]   rj   BaseRequestHandlerrk   r   ThreadingMixInr   r   r   objectr   ri  ro  r  r  r   r   r   r   r   <module>   s   	"
#    
;


Q3	#
        }K
 
,
