a
    0s/h&{  ã                   @   sd  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	Z	ddl
Z
ddlZddlmZ ddlmZ ddlZddlZddlZddlZddlmZmZ G dd„ dejƒZG dd	„ d	ejƒZd
d„ Ze
je
je
jB e
j B e
j!B e
je
jB e
j B e
j!B e
j"B e
je
jB e
j B e
j!B e
j"B e
j#B dœZ$dd„ Z%dd„ Z&G dd„ deeƒZ'e(dkr`e&ƒ  dS )aV  
A WebSocket to TCP socket proxy with support for "wss://" encryption.
Copyright 2011 Joel Martin
Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)

You can make a cert/key with openssl using:
openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
as taken from http://docs.python.org/dev/library/ssl.html#certificates

é    N)ÚThreadingMixIn)Ú
HTTPServer)Úparse_qsÚurlparsec                   @   sD   e Zd ZdZdZdd„ Zdd„ Zdd„ Zd	d
„ Zdd„ Z	dd„ Z
dS )ÚProxyRequestHandleré   zÆ
Traffic Legend:
    }  - Client receive
    }. - Client receive partial
    {  - Target receive

    >  - Target send
    >. - Target send partial
    <  - Client send
    <. - Client send partial
c                 C   sH   |   |j|j¡ |  dd¡ |j ¡ D ]\}}|  ||¡ q&|  ¡  d S )NzContent-Typez	text/html)Úsend_responseÚcodeÚmsgÚsend_headerÚheadersÚitemsÚend_headers)ÚselfÚexÚnameÚval© r   ú3/opt/jumpscale7/apps/vncproxy/utils/./websockify.pyÚsend_auth_error(   s
    z#ProxyRequestHandler.send_auth_errorc                 C   sD   | j jsd S |  | j j¡\}}|dkr0|| j _n|| j _|| j _d S )NÚunix_socket)ÚserverÚtoken_pluginÚ
get_targetÚunix_targetÚtarget_hostÚtarget_port)r   ÚhostÚportr   r   r   Úvalidate_connection0   s    
z'ProxyRequestHandler.validate_connectionc              
   C   sÒ   | j jsd S dd„ | jD ƒ}|D ]}| j|= q z6| j ¡ }|d }tdd„ |D ƒƒ}|d | jd< W n tttfy|   Y n0 z"| j jj	| j| j j
| j jd W n, tjyÌ   t ¡ d }|  |¡ ‚ Y n0 d S )	Nc                 S   s   g | ]}|  d ¡r|‘qS )ZSSL_)Ú
startswith)Ú.0Úhr   r   r   Ú
<listcomp>B   ó    z7ProxyRequestHandler.auth_connection.<locals>.<listcomp>Úsubjectc                 S   s   g | ]}|d  ‘qS )r   r   )r!   Úxr   r   r   r#   L   r$   Ú
commonNameZSSL_CLIENT_S_DN_CN)r   r   r   é   )r   Úauth_pluginr   ÚrequestÚgetpeercertÚdictÚ	TypeErrorÚAttributeErrorÚKeyErrorZauthenticater   r   ÚauthZAuthenticationErrorÚsysÚexc_infor   )r   Zssl_headersr"   Zclient_cert_dataZclient_cert_subjectr   r   r   r   Úauth_connection<   s*    


þ

z#ProxyRequestHandler.auth_connectionc                 C   sÚ  | j jr&|  | j j| j¡\| j _| j _| j jrJdd | j j¡| j jf }n*| j jr`d| j j }nd| j j| j jf }| j j	r„|d7 }|  
|¡ z*tjj| j j| j jd| j j	| j jd}W nJ ty } z0|  
d| j j| j j|¡ |  d	d
¡‚W Y d}~n
d}~0 0 | j js"| j tjtjd¡ | j jsH| j jsH| tjtjd¡ |  | j¡ zF|  |¡ W |rÖ| tj¡ | ¡  | jrÖ|  
d| j j| j j¡ n:|rÔ| tj¡ | ¡  | jrÔ|  
d| j j| j j¡ 0 dS )zO
        Called after a new WebSocket connection has been established.
        z%connecting to command: '%s' (port %s)Ú zconnecting to unix socket: %szconnecting to: %s:%sú (using SSL)T)ÚconnectZuse_sslr   zFailed to connect to %s:%s: %sió  z&Failed to connect to downstream serverNr(   z%s:%s: Closed target)r   Ú
target_cfgr   Úpathr   r   Úwrap_cmdÚjoinr   Ú
ssl_targetÚlog_messageÚwebsockifyserverÚWebSockifyServerÚsocketÚ	ExceptionÚCCloseÚunix_listenr*   Ú
setsockoptÚSOL_TCPÚTCP_NODELAYÚprint_trafficÚtraffic_legendÚdo_proxyÚshutdownÚ	SHUT_RDWRÚcloseÚverbose)r   r
   ZtsockÚer   r   r   Únew_websocket_client\   sZ    ÿ
ü
ÿ"
ÿüÿz(ProxyRequestHandler.new_websocket_clientc                 C   s¢   | j r&| j d¡}|rd| d¡d }n>tt| jƒd ƒ}d|v r`t|d ƒr`|d d  d¡}nd}|du rx| j	 
d¡‚| |¡}|durŽ|S | j	 
d	| ¡‚dS )
zò
        Gets a token from either the path or the host,
        depending on --host-token, and looks up a target
        for that token using the token plugin. Used by
        validate_connection() to set target_host and target_port.
        ÚHostú:r   é   ÚtokenÚ
NzToken not presentzToken '%s' not found)Ú
host_tokenr   ÚgetÚ	partitionr   r   r8   ÚlenÚrstripr   ÚECloseÚlookup)r   Ztarget_pluginrR   ÚargsZresult_pairr   r   r   r      s    

zProxyRequestHandler.get_targetc                 C   sÀ  g }d}g }| j |g}| jjr6t ¡ }|| jj | _nd| _g }| jdurrt ¡ }|| jkrr|| jj | _|  ¡  |r€| |¡ |sˆ|r”| | j ¡ zt ||g d¡\}}	}
W nJ tyø   t 	¡ d }t
|dƒrÚ|j}n|d }|tjkrð‚ nY q<Y n0 |
rtdƒ‚| j |	v r"|  |¡}g }| j |v rÚ|  ¡ \}}| |¡ |rÚt|ƒdkr¨| d¡}| |¡}|t|ƒkr†|  d¡ n| d||d… ¡ |  d¡ qJ| jrÆ|  d| jj| jj¡ |  |d	 |d
 ¡‚||	v r0| d¡}| |¡}|t|ƒkr|  d¡ n| d||d… ¡ |  d¡ ||v r<| | j¡}t|ƒdkr¦t|ƒdkr|d}|rx|  |¡}qdg }| jrš|  d| jj| jj¡ |  dd¡‚| |¡ |  d¡ q<dS )zA
        Proxy client WebSocket to normal target socket.
        r   Nr(   ÚerrnozSocket exceptionú>z.>z%s:%s: Client closed connectionr	   ÚreasonTz%s:%s: Target closed connectioniè  zTarget closedú{)r*   r   Ú	heartbeatÚtimeZ	send_pingÚappendÚselectÚOSErrorr1   r2   Úhasattrr\   ZEINTRr@   Zsend_framesZrecv_framesÚextendrW   ÚpopÚsendrF   ÚinsertrL   r<   r   r   rA   ÚrecvÚbuffer_size)r   ÚtargetZcqueueZc_pendZtqueueZrlistÚnowZwlistZinsZoutsZexceptsÚexcÚerrZbufsÚclosedZdatÚsentÚbufr   r   r   rH   ¶   sˆ    









ÿ



ÿ
zProxyRequestHandler.do_proxyN)Ú__name__Ú
__module__Ú__qualname__rk   rG   r   r   r3   rN   r   rH   r   r   r   r   r      s    3'r   c                       s@   e Zd ZdZdZef‡ fdd„	Zdd„ Zdd„ Zd	d
„ Z	‡  Z
S )ÚWebSocketProxyza
    Proxy traffic to and from a WebSockets client to a normal TCP
    socket server target.
    r   c           
         sÜ  |  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  d	d ¡| _	|  d
d ¡| _
|  dd ¡| _g d¢| _| jr¾tj tjd ¡}tj |dd¡tj |ddd¡tj |d¡|g}d | _|D ]*}tj |d¡}tj |¡rø|| _ q$qø| js4tdƒ‚tj | j¡| _d| _t tjtj¡}| d¡ | ¡ d | _| ¡  td | jtj dd ¡gƒ}	tj  tj! |	¡t"|d ƒt"| jƒdœ¡ t#ƒ j$|g|¢R i |¤Ž d S )Nr   r   r9   Ú	wrap_moder   r;   r`   r   rT   r)   r7   )r   r   r   r   z..ÚlibÚ
websockifyz	rebind.soz1rebind.so not found, perhaps you need to run makez	127.0.0.1)Ú r   r(   Ú
LD_PRELOADÚlisten_port)r{   ZREBIND_OLD_PORTZREBIND_NEW_PORT)%rg   r   r   r9   rw   r   r;   r`   r   rT   r)   r7   Ú
wrap_timesÚosr8   Údirnamer1   Úargvr:   ZrebinderÚexistsr@   Úabspathr?   ÚAF_INETÚSOCK_STREAMÚbindÚgetsocknamerK   ÚfilterÚenvironrU   ÚupdateÚpathsepÚstrÚsuperÚ__init__)
r   ÚRequestHandlerClassr[   ÚkwargsZwsdirZrebinder_pathZrdirZrpathÚsockZld_preloads©Ú	__class__r   r   r   )  sP    
ý


ýzWebSocketProxy.__init__c                 C   sP   |   dd | j¡¡ | j t ¡ ¡ | j d¡ tj| jt	j
td| _d| _d S )NzStarting '%s'r4   r   )ÚenvZ
preexec_fnT)r
   r:   r9   r}   rb   ra   rg   Ú
subprocessÚPopenr~   rˆ   Ú_subprocess_setupÚcmdÚspawn_message)r   r   r   r   Úrun_wrap_cmd]  s    
ÿzWebSocketProxy.run_wrap_cmdc                 C   s°   | j rdd | j ¡| jf }n| jr,| j}nd| j| jf }| jdkrLd}nd| j| jf }| jrxd|t	| jƒj
f }nd||f }| jr’|d7 }|  d	|¡ | j r¬|  ¡  dS )
zO
        Called after Websockets server startup (i.e. after daemonize)
        z'%s' (port %s)r4   z%s:%sNÚinetdz/  - proxying from %s to targets generated by %sz  - proxying from %s to %sr5   z%s)r9   r:   r   r   r   Ú	listen_fdÚlisten_hostr|   r   Útypers   r;   r
   r™   )r   Z
dst_stringZ
src_stringr
   r   r   r   Ústartede  s(    
ÿÿzWebSocketProxy.startedc                 C   sº   | j r2| jr2| j ¡ }|d kr2|  d| ¡ d | _| j r¶| jd kr¶| jdkrNnh| jdkrdt |¡ nR| jdkr¶t ¡ }t| j	ƒt
| j	ƒ }|| dk r®| jr¶|  d¡ d| _n|  ¡  d S )Nz/Wrapped command exited (or daemon). Returned %sÚignoreÚexitÚrespawné
   zCommand respawning too fastF)r9   r—   ÚpollZvmsgrw   r1   r    ra   Úsumr}   rW   r˜   Úwarnr™   )r   Úretrm   Zavgr   r   r   r£   †  s$    




zWebSocketProxy.poll)rs   rt   ru   Ú__doc__rk   r   r   r™   rž   r£   Ú__classcell__r   r   r‘   r   rv   !  s   4!rv   c                   C   s   t   t jt j¡ d S )N)ÚsignalÚSIGPIPEÚSIG_DFLr   r   r   r   r–   ¡  s    r–   ©ÚdefaultZtlsv1_1Ztlsv1_2Ztlsv1_3c                 C   sR   | t v rt |  S tt  ¡ ƒ}| ¡  |d }t tj¡}| d| |¡ t | S dS )zXReturns SSL options for the most secure TSL version available on this
    Python versionéÿÿÿÿz.TLS version %s unsupported. Falling back to %sN)	ÚSSL_OPTIONSÚlistÚkeysÚsortÚloggingÚ	getLoggerrv   Ú
log_prefixr¥   )Úversionr±   ÚfallbackÚloggerr   r   r   Úselect_ssl_version±  s    ÿr¹   c                  C   sn  t  ¡ } |  t j¡ t  d¡}|  |¡ t  ¡ }| | ¡ | t j¡ d}|d7 }|d7 }|d7 }|d7 }|d7 }|d7 }|d7 }t	j
|d}|jdd	d
dd |jdd
dd |jdddd |jdddd
dd |jdd
dd |jdtddd |jdtddd |jd d!d"d# |jd$d d%d# |jd&d d'd# |jd(d
d)d |jd*d
d+d |jd,d
d-d |jd.dd/d0 |jd1d2d3g d4¢d5d6d7 |jd8d5d9d |jd:d;dd d< |jd=d d>d# |jd?d@dd |jdAdBd
dC |jdDd dEdFdG |jdHd
dId |jdJdKdLg dM¢dNdO |jdPdQd
dRdSdT |jdUd
dVd |jdWddXdYdZ |jd[d d\d]dG |jd^d d_d`dG |jdad
dbd |jdcd d\dddG |jded d_dfdG |jdgtddhdidj |jdkddldmdZ |jdnd dodpdG |jdqd
drd |jdsd
dtd | ¡ \}}|jr*|js*| du¡ |jrD|jsD| dv¡ |jr^|js^| dw¡ |jrx|jsx| dx¡ |jr’|js’| dy¡ |jr¬|js¬| dz¡ t|jƒ|_|`|jrtj |j¡|_t  |j¡}| t j¡ | |¡ t  ¡ }| |¡ |`|jrÔ|j  d{¡rj|j !d{d|¡\}}	zt|	ƒ}	W n t"y^   | d}¡ Y n0 ||	f}
ntj |j¡}
dd~l#m$} |j%r”|j&}n|j'}||
|d|jd€}| t j¡ | |¡ t  ¡ }| |¡ |`|`|j(røt  ¡ }| t j¡ |j)rtj |j)¡|_)|j)r&d|_|j)|_|`)t*j+  d‚¡rH|d|d … |_,nd |_,t-j.sh|j/rh| dƒ¡ |j0rtj 1|j2¡s| d„|j2 ¡ |j3r¦t*j4 5¡ |_6nè|j7rú|j8rêzt|j8d…ƒ|_8W n t"yæ   | d†¡ Y n0 nt9j:t9j;B |_8n”t<|ƒd|k r| d‡¡ | =d¡}|  d{¡dkrP| !d{d|¡\|_>|_?|j> @dˆ¡|_>nd‰| |_>|_?zt|j?ƒ|_?W n t"yŒ   | dŠ¡ Y n0 |`3|j,sª|jAsª|jr¸d |_Bd |_Cnt<|ƒd|k rÐ| d‡¡ | =d¡}|  d{¡dkr| !d{d|¡\|_B|_C|jB @dˆ¡|_Bn
| d‹¡ zt|jCƒ|_CW n t"yF   | dŒ¡ Y n0 t<|ƒdkrl|j,d krl| d¡ |jd urÆdŽ|jvrd|j |_|j !dŽd|¡\}}tD|ƒ tEt*jF| |ƒ}||jƒ|_|`|jd ur$dŽ|jvrîd|j |_|j !dŽd|¡\}}tD|ƒ tEt*jF| |ƒ}||jƒ|_|`|jG}|`G|rRtHf i |jI¤Ž}| J¡  ntKf i |jI¤Ž}| L¡  d S )‘Nz%(message)sz
    %prog [options]z2 [source_addr:]source_port target_addr:target_portz/ --token-plugin=CLASS [source_addr:]source_portz- --unix-target=FILE [source_addr:]source_portz/ [source_addr:]source_port -- WRAP_COMMAND_LINE)Úusagez	--verbosez-vÚ
store_truezverbose messages)ÚactionÚhelpz	--trafficzper frame trafficz--recordz(record sessions to FILE.[session_number]ÚFILE)r½   Úmetavarz--daemonz-DÚdaemonz$become a daemon (background process))Údestr¼   r½   z
--run-oncez-handle a single WebSocket connection and exitz	--timeoutr   z-after TIMEOUT seconds exit when not connected)r   r­   r½   z--idle-timeoutzEserver exits after TIMEOUT seconds if there are no active connectionsz--certzself.pemzSSL certificate file)r­   r½   z--keyz$SSL key file (if separate from cert)z--key-passwordzSSL key passwordz
--ssl-onlyz)disallow non-encrypted client connectionsz--ssl-targetz#connect to SSL target as SSL clientz--verify-clientzlrequire encrypted client to present a valid certificate (needs Python 2.7.9 or newer or Python 3.4 or newer)z--cafilez¦file of concatenated certificates of authorities trusted for validating clients (only effective with --verify-client). If omitted, system default list of CAs is used.)r¿   r½   z--ssl-versionÚchoicer­   r¬   Ústorez?minimum TLS version to use (default, tlsv1_1, tlsv1_2, tlsv1_3))r   r­   Úchoicesr¼   r½   z--ssl-ciphersz]list of ciphers allowed for connection. For a list of supported ciphers run `openssl ciphers`z--unix-listenzlisten to unix socket)r½   r¿   r­   z--unix-listen-modez/specify mode for unix socket (defaults to 0600)z--unix-targetzconnect to unix socket targetz--inetdz/inetd mode, receive listening socket from stdin)r½   r¼   z--webÚDIRz1run webserver on same port. Serve files from DIR.)r­   r¿   r½   z
--web-authz+require authentication to access webserver.z--wrap-moder    ÚMODE)r    rŸ   r¡   z\action to take when the wrapped program exits or daemonizes: exit (default), ignore, respawn)r­   r¿   rÄ   r½   z--prefer-ipv6z-6Úsource_is_ipv6z&prefer IPv6 when resolving source_addr)r¼   rÁ   r½   z--libserverz&use Python library SocketServer enginez--target-configr7   zíConfiguration file containing valid targets in the form 'token: host:port' or, alternatively, a directory containing configuration files of this form (DEPRECATED: use `--token-plugin TokenFile --token-source  path/to/token/file` instead))r¿   rÁ   r½   z--token-pluginZCLASSzxuse a Python class, usually one from websockify.token_plugins, such as TokenFile, to process tokens into host:port pairsz--token-sourceZARGz=an argument to be passed to the token plugin on instantiationz--host-tokenzJuse the host HTTP header as token instead of the token URL query parameterz--auth-pluginz|use a Python class, usually one from websockify.auth_plugins, such as BasicHTTPAuth, to determine if a connection is allowedz--auth-sourcez<an argument to be passed to the auth plugin on instantiationz--heartbeatZINTERVALz0send a ping to the client every INTERVAL seconds)r   r­   r¿   r½   z
--log-fileÚlog_filezFile where logs will be savedz--syslogZSERVERz\Log to syslog server. SERVER can be local socket, such as /dev/log, or a UDP host:port pair.z--legacy-syslogzoUse the old syslog protocol instead of RFC 5424. Use this if the messages produced by websockify seem abnormal.z--file-onlyz5use this to disable directory listings in web server.z1You must use --token-plugin to use --token-sourcez/You must use --token-plugin to use --host-tokenz/You must use --auth-plugin to use --auth-sourcez,You must use --auth-plugin to use --web-authz$You must use --web to use --web-authz,You must use --syslog to use --legacy-syslogrP   r(   zError parsing syslog port)ÚWebsockifySysLogHandlerry   )ÚaddressZfacilityÚidentZlegacyZ	TokenFilez--z6SSL target requested and Python SSL module not loaded.zSSL only and %s not foundé   z%Error parsing listen unix socket modezToo few argumentsz[]rz   zError parsing listen portzError parsing targetzError parsing target portzToo many argumentsÚ.zwebsockify.token_plugins.%szwebsockify.auth_plugins.%s)Mr³   ÚStreamHandlerÚsetLevelÚDEBUGÚ	FormatterÚsetFormatterr´   Ú
addHandlerÚINFOÚoptparseÚOptionParserÚ
add_optionÚintÚ
parse_argsZtoken_sourcer   ÚerrorrT   Zauth_sourcer)   Zweb_authÚwebZlegacy_syslogZsyslogr¹   Ússl_versionZssl_optionsrÈ   r~   r8   r‚   ÚFileHandlerÚcountÚrsplitÚ
ValueErrorZwebsockify.sysloghandlerrÉ   rÀ   Z
LOG_DAEMONZLOG_USERrL   r7   r1   r€   r9   r=   Ússlr;   Ússl_onlyr   Úcertrš   ÚstdinÚfilenor›   rB   Zunix_listen_modeÚstatÚS_IREADÚS_IWRITErW   rg   rœ   r|   Ústripr   r   r   Ú
__import__ÚgetattrÚmodulesÚ	libserverÚLibProxyServerÚ__dict__Úserve_foreverrv   Ústart_server)Zstderr_handlerZlog_formatterÚrootrº   ÚparserÚoptsr[   Zlog_file_handlerZsyslog_hostZsyslog_portZsyslog_destrÉ   Zsyslog_facilityZsyslog_handlerÚargZtoken_plugin_moduleZtoken_plugin_clsZauth_plugin_moduleZauth_plugin_clsrí   r   r   r   r   Úwebsockify_initÂ  sü   



ÿÿÿþÿ
ÿ
ÿÿÿÿÿÿÿÿ
þÿÿÿÿÿ
ÿÿ
þþÿþ
ÿ
ÿÿ
ÿ
ÿÿþ
ÿÿÿ








ý








ÿ
rö   c                       s0   e Zd ZdZef‡ fdd„	Z‡ fdd„Z‡  ZS )rî   zX
    Just like WebSocketProxy, but uses standard Python SocketServer
    framework.
    c                    sR  |  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  dd ¡| _|  d	d ¡| _	|  d
d ¡| _
d | _
d | _d | _d| _|  dd¡}|  dd ¡}|  dd¡}| | _|  dd¡| _|  dd¡}|rütj |¡| _|  dd¡| _d| _| ¡ D ]}td| ƒ q|r<t |¡ tƒ  ||f|¡ d S )Nr   r   r9   rw   r   r;   r   r)   r`   r7   Frœ   rz   r|   rÛ   rL   ÚrecordÚrun_oncer   z1warning: option %s ignored when using --libserver)rg   r   r   r9   rw   r   r;   r   r)   r`   r7   rÀ   Zonly_upgraderL   r~   r8   r‚   r÷   rø   Ú
handler_idr±   ÚprintÚchdirrŒ   r   )r   rŽ   r   rœ   r|   rÛ   r÷   rõ   r‘   r   r   r   û  s:    
zLibProxyServer.__init__c                    s    |  j d7  _ tƒ  ||¡ dS )z/Override process_request to implement a counterr(   N)rù   rŒ   Úprocess_request)r   r*   Zclient_addressr‘   r   r   rü   $  s    zLibProxyServer.process_request)rs   rt   ru   r§   r   r   rü   r¨   r   r   r‘   r   rî   õ  s   )rî   Ú__main__))r§   r©   r?   rÕ   ra   r~   r1   r”   r³   r\   rá   ræ   Zsocketserverr   Zhttp.serverr   rc   Ú	websocketr=   Zauth_pluginsr0   Úurllib.parser   r   ZWebSockifyRequestHandlerr   r>   rv   r–   ÚOP_ALLÚPROTOCOL_SSLv23ÚOP_NO_SSLv2ÚOP_NO_SSLv3ÚOP_NO_TLSv1ÚOP_NO_TLSv1_1ÚOP_NO_TLSv1_2r¯   r¹   rö   rî   rs   r   r   r   r   Ú<module>   sL   X   ÿÿÿÿÿÿú
  55
