a
    Na36?                   @   s   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mZ ddl	m
Z
 ddlmZmZmZmZmZmZmZ ddlmZmZ ddlmZmZ ddlmZ d	d
 ZG dd deZdd ZG dd deZ dS )z
Packet handling
    N)HMAC)util)linefeed_bytecr_byte_valueasbytes	MSG_NAMESDEBUG	xffffffff	zero_byte)ubyte_ord)SSHExceptionProxyCommandFailure)Messagec                 C   s   t | || S N)r   Zdigest)keymessageZdigest_class r   3/usr/lib/python3.9/site-packages/paramiko/packet.pycompute_hmac.   s    r   c                   @   s   e Zd ZdZdS )NeedRekeyExceptionz1
    Exception indicating a rekey is needed.
    N)__name__
__module____qualname____doc__r   r   r   r   r   2   s   r   c                 C   s.   d }t | jtu r*t| jdkr*| jd }|S )Nr   )typeargstuplelen)eargr   r   r   	first_arg:   s    
r!   c                   @   s"  e Zd ZdZeddZeddZeddZeddZdd Z	e
dd Zdd	 Zd>ddZd?ddZdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd@d)d*Zd+d, Zd-d. Zd/d0 Zd1d2 Z d3d4 Z!d5d6 Z"d7d8 Z#d9d: Z$d;d< Z%d=S )A
Packetizerz9
    Implementation of the base SSH packet protocol.
          c                 C   s   || _ d | _d| _d| _d| _d| _t | _d| _d| _	d| _
d| _d| _d| _d| _d| _d| _d| _d | _d | _d| _d | _d | _t | _t | _d | _d | _d| _d| _d| _d| _t  | _!d| _"t## | _$d | _%d | _&d| _'d| _(d S )NFr      ))_Packetizer__socket_Packetizer__logger_Packetizer__closed_Packetizer__dump_packets_Packetizer__need_rekey_Packetizer__init_countbytes_Packetizer__remainder_Packetizer__sent_bytes_Packetizer__sent_packets_Packetizer__received_bytes_Packetizer__received_packets$_Packetizer__received_bytes_overflow&_Packetizer__received_packets_overflow_Packetizer__block_size_out_Packetizer__block_size_in_Packetizer__mac_size_out_Packetizer__mac_size_in_Packetizer__block_engine_out_Packetizer__block_engine_in_Packetizer__sdctr_out_Packetizer__mac_engine_out_Packetizer__mac_engine_in_Packetizer__mac_key_out_Packetizer__mac_key_in _Packetizer__compress_engine_out_Packetizer__compress_engine_in _Packetizer__sequence_number_out_Packetizer__sequence_number_in_Packetizer__etm_out_Packetizer__etm_in	threadingRLock_Packetizer__write_lock_Packetizer__keepalive_intervaltime_Packetizer__keepalive_last_Packetizer__keepalive_callback_Packetizer__timer_Packetizer__handshake_complete_Packetizer__timer_expired)selfsocketr   r   r   __init__Q   sJ    

zPacketizer.__init__c                 C   s   | j S r   )r(   rO   r   r   r   closed   s    zPacketizer.closedc                 C   s
   || _ dS )z?
        Set the Python log object to use for logging.
        N)r'   )rO   logr   r   r   set_log   s    zPacketizer.set_logFc                 C   s^   || _ || _|| _|| _|| _|| _d| _d| _|| _|  j	dO  _	| j	dkrZd| _	d| _
dS )zd
        Switch outbound data cipher.
        :param etm: Set encrypt-then-mac from OpenSSH
        r         FN)r8   r:   r4   r;   r6   r=   r.   r/   rC   r+   r*   )rO   block_engine
block_size
mac_enginemac_sizemac_keyZsdctretmr   r   r   set_outbound_cipher   s    
zPacketizer.set_outbound_cipherc                 C   sd   || _ || _|| _|| _|| _d| _d| _d| _d| _|| _	|  j
dO  _
| j
dkr`d| _
d| _dS )zc
        Switch inbound data cipher.
        :param etm: Set encrypt-then-mac from OpenSSH
        r   r#   rW   FN)r9   r5   r<   r7   r>   r0   r1   r2   r3   rD   r+   r*   )rO   rX   rY   rZ   r[   r\   r]   r   r   r   set_inbound_cipher   s    
zPacketizer.set_inbound_cipherc                 C   s
   || _ d S r   )r?   rO   Z
compressorr   r   r   set_outbound_compressor   s    z"Packetizer.set_outbound_compressorc                 C   s
   || _ d S r   )r@   r`   r   r   r   set_inbound_compressor   s    z!Packetizer.set_inbound_compressorc                 C   s   d| _ | j  d S NT)r(   r&   closerR   r   r   r   rd      s    zPacketizer.closec                 C   s
   || _ d S r   r)   )rO   Zhexdumpr   r   r   set_hexdump   s    zPacketizer.set_hexdumpc                 C   s   | j S r   re   rR   r   r   r   get_hexdump   s    zPacketizer.get_hexdumpc                 C   s   | j S r   )r7   rR   r   r   r   get_mac_size_in   s    zPacketizer.get_mac_size_inc                 C   s   | j S r   )r6   rR   r   r   r   get_mac_size_out   s    zPacketizer.get_mac_size_outc                 C   s   | j S )z
        Returns ``True`` if a new set of keys needs to be negotiated.  This
        will be triggered during a packet read or write, so it should be
        checked after every read or write, or at least after every few.
        r*   rR   r   r   r   
need_rekey   s    zPacketizer.need_rekeyc                 C   s   || _ || _t | _dS )z
        Turn on/off the callback keepalive.  If ``interval`` seconds pass with
        no data read from or written to the socket, the callback will be
        executed and the timer will be reset.
        N)rH   rK   rI   rJ   )rO   intervalcallbackr   r   r   set_keepalive   s    zPacketizer.set_keepalivec                 C   s
   d| _ d S rc   )rN   rR   r   r   r   
read_timer   s    zPacketizer.read_timerc                 C   s(   | j s$tt|| j| _ | j   dS )z
        Tells `Packetizer` that the handshake process started.
        Starts a book keeping timer that can signal a timeout in the
        handshake process.

        :param float timeout: amount of seconds to wait before timing out
        N)rL   rE   Timerfloatro   start)rO   timeoutr   r   r   start_handshake   s    zPacketizer.start_handshakec                 C   s   | j s
dS | jrdS | jS )aR  
        Checks if the handshake has timed out.

        If `start_handshake` wasn't called before the call to this function,
        the return value will always be `False`. If the handshake completed
        before a timeout was reached, the return value will be `False`

        :return: handshake time out status, as a `bool`
        F)rL   rM   rN   rR   r   r   r   handshake_timed_out   s
    
zPacketizer.handshake_timed_outc                 C   s    | j r| j   d| _d| _dS )zF
        Tells `Packetizer` that the handshake has completed.
        FTN)rL   cancelrN   rM   rR   r   r   r   complete_handshake  s    
zPacketizer.complete_handshakec              
   C   sF  t  }t| jdkr>| jd| }| j|d | _|t|8 }|dkrBd}|  rZt z6| j|}t|dkrzt ||7 }|t|8 }W nr tjy   d}Y n\ tj	y } z@t
|}|tjkrd}n|tjkrn| jrt n W Y d}~n
d}~0 0 |r>| jrt |r8t|dkr8| jr8t |   q>|S )a&  
        Read as close to N bytes as possible, blocking as long as necessary.

        :param int n: number of bytes to read
        :return: the data read, as a `str`

        :raises:
            ``EOFError`` -- if the socket was closed before all the bytes could
            be read
        r   NFT)r,   r   r-   ru   EOFErrorr&   recvrP   rs   errorr!   errnoEAGAINEINTRr(   r*   r   _check_keepalive)rO   ncheck_rekeyoutZgot_timeoutxr   r    r   r   r   read_all  sB    



zPacketizer.read_allc              
   C   s"  t   | _d}t|dkrd}z| j|}W n tjyH   d}Y nx tjy } z8t|}|t	j
krpd}n|t	jkrd}nd}W Y d }~n0d }~0  ty    Y n ty   d}Y n0 |rd}| jrd}n|dkr|dkrd}|d7 }|dk rt |t|krq||d  }qd S )Nr   FT
   rV   )rI   rJ   r   r&   sendrP   rs   rz   r!   r{   r|   r}   r   	Exceptionr(   rx   )rO   r   Z#iteration_with_zero_as_return_valueZretry_writer   r   r    r   r   r   	write_allJ  s@    



zPacketizer.write_allc                 C   sr   | j }t|vr|| |7 }q|t}||d d | _ |d| }t|dkrj|d tkrj|dd }t|S )z
        Read a line from the socket.  We assume no data is pending after the
        line, so it's okay to attempt large reads.
        rV   Nr   r   )r-   r   _read_timeoutindexr   r   r   )rO   rs   bufr   r   r   r   readlineu  s    
zPacketizer.readlinec                 C   s  t |}t|d }|tv r&t| }n
d|}t|}| j  zz| jdurZ| |}| |}| j	r| 
td|| | 
tt|d | jdur| jr|dd | j|dd  }q| j|}n|}| jdur td| j}|| jr|n| }|t| j|| jd| j 7 }| jd t@ | _| | |  jt|7  _|  jd7  _| j| jkpr| j| jk}	|	r| jsd	}
| 
t|
| j| j d| _d| _ | !  W | j"  n| j"  0 dS )
zR
        Write a block of data using the current cipher, as an SSH block.
        r   ${:x}NzWrite packet <{}>, length {}zOUT:    >IrV   z(Rekeying (hit {} packets, {} bytes sent))#r   r   r   formatr   rG   acquirer?   _build_packetr)   _logr   r   format_binaryr8   rC   updatestructpackrA   r   r=   r;   r6   r	   r   r.   r/   REKEY_PACKETSREKEY_BYTESr*   r2   r3   _trigger_rekeyrelease)rO   datacmdcmd_nameZorig_lenpacketr   ZpackedpayloadZsent_too_muchmsgr   r   r   send_message  sd    












zPacketizer.send_messagec                 C   s  | j | jdd}| jrtd|dd d }|| j d }|dd | j |dd }| j | jdd}td| j|| }t| j	|| j
d| j }t||std	|}| jdur| j|}| jr| tt|d
 | jr|}ntd|dd d }|dd }|t| | j dkr,td|  || j t| }	|	d|t|  }|	|t| d }
| jdur| j|}|| }| jr| tt|d
 | jdkr| js|
d| j }td| j|| }t| j	|| j
d| j }t||std	t|d }|d||  }| jrF| td|| | jdur\| |}t|dd }| j|_| jd t@ | _|| j d }|  j|7  _|  jd7  _| jr|  j|7  _|  jd7  _| j| j ks| j| j!krDtdnL| j| j"ks| j| j#krDd}| t|| j| j d| _d| _| $  t|d }|t%v rdt%| }n
d|}| jr| td|t| ||fS )z
        Only one thread should ever be in this function (no other locking is
        done).

        :raises: `.SSHException` -- if the packet is mangled
        :raises: `.NeedRekeyException` -- if the transport should rekey
        T)r   r   Nr   r   Fz>IIzMismatched MACzIN: zInvalid packet blockingrV   z"Got payload ({} bytes, {} padding)z+Remote transport is ignoring rekey requestsz,Rekeying (hit {} packets, {} bytes received)r   zRead packet <{}>, length {})&r   r5   rD   r   unpackr7   r   rB   r   r>   r<   r   Zconstant_time_bytes_eqr   r9   r   r)   r   r   r   r   r   r   r@   r   Zseqnor	   r0   r1   r*   r2   r3   REKEY_PACKETS_OVERFLOW_MAXREKEY_BYTES_OVERFLOW_MAXr   r   r   r   )rO   headerZpacket_sizeZ	remainingr   ZmacZmac_payloadZmy_macZleftoverr   Zpost_packetpaddingr   r   Zraw_packet_sizeerrr   r   r   r   r   read_message  s    








zPacketizer.read_messagec                 C   sH   | j d u rd S tt|tr6|D ]}| j || q n| j || d S r   )r'   
issubclassr   listrT   )rO   levelr   mr   r   r   r   E  s    
zPacketizer._logc                 C   s@   | j r| jr| jrd S t }|| j| j  kr<|   || _d S r   )rH   r8   r*   rI   rJ   rK   )rO   nowr   r   r   r~   N  s    zPacketizer._check_keepalivec              
   C   s   t   }z&| jd}t|dkr(t W qW nH tjyB   Y n6 tyv } zt|t	j
kr`n W Y d }~n
d }~0 0 | jrt t   }|| |krt q|S )N   r   )rI   r&   ry   r   rx   rP   rs   EnvironmentErrorr!   r{   r}   r(   )rO   rs   rr   r   r   r   r   r   r   r   [  s$    
zPacketizer._read_timeoutc                 C   s~   | j }| jrdnd}d| t|| |  }tdt|| d |}||7 }| js^| jd u rl|t| 7 }n|t	|7 }|S )Nr   r%   rW   z>IBrV   )
r4   rC   r   r   r   r:   r8   r
   osurandom)rO   r   ZbsizeZaddlenr   r   r   r   r   r   q  s    zPacketizer._build_packetc                 C   s
   d| _ d S rc   rj   rR   r   r   r   r     s    zPacketizer._trigger_rekeyN)FF)F)F)&r   r   r   r   powr   r   r   r   rQ   propertyrS   rU   r^   r_   ra   rb   rd   rf   rg   rh   ri   rk   rn   ro   rt   ru   rw   r   r   r   r   r   r   r~   r   r   r   r   r   r   r   r"   A   sL   



0
  
% 

	
3+? 	r"   )!r   r{   r   rP   r   rE   rI   Zhmacr   Zparamikor   Zparamiko.commonr   r   r   r   r   r	   r
   Zparamiko.py3compatr   r   Zparamiko.ssh_exceptionr   r   Zparamiko.messager   r   r   r   r!   objectr"   r   r   r   r   <module>   s    $	