Code Monkey home page Code Monkey logo

Comments (14)

onokonem avatar onokonem commented on May 29, 2024

I did not find "attach file"

So it is published just as a comment. I hope it will not be damaged by formatter.

# websockify proxy to serve noVNC (http://kanaka.github.com/noVNC/)
# with Apache + mod_python + pywebsocket
# Inspired by websockify project (https://github.com/kanaka/websockify)
#
# Supports noVNC path feature
# but in different way than original websockify do:
# GET parameters have to be specified
# like http://your.host.dom/vnc/ws/websockify?host=localhost&port=5900
#  or just http://your.host.dom/vnc/ws/websockify?port=5900
#  as localhost is default
#
# Created by Daniel Podolsky, [email protected], 22 Nov 2011
#
# Install
# 1) Install Apache 2.2 (http://httpd.apache.org/) with mod_python
# 2) Install pywebsocket (http://code.google.com/p/pywebsocket/)
# 3) Place websockify_wsh.py somewhere. Say, /var/www/vnc/ws/websockify_wsh.py
# 4) Configure apache:
#   PythonOption mod_pywebsocket.handler_root /var/www/vnc
#   PythonOption mod_pywebsocket.handler_scan /var/www/vnc/ws
#   
#   <Location /vnc/ws>
#     PythonHeaderParserHandler mod_pywebsocket.headerparserhandler
#     PythonDebug On
#   </Location>
#
# Note: 'PythonOption mod_pywebsocket.handler_*' must be placed
#  in the global Apache config scope
# (see http://www.mailinglistarchive.com/html/[email protected]/2006-09/msg00720.html)

import socket

from sys             import exc_info
from urlparse        import parse_qs
from base64          import b64encode, b64decode
from mod_python      import apache
from mod_pywebsocket import msgutil

def list_value(array, key, def_val=None):
    if key in array:
        return array[key]
    if def_val is not None:
        return def_val
    raise ValueError("websockify: '%s' is not specified" % (key))


def web_socket_do_extra_handshake(request):
    request.ws_protocol = request.ws_requested_protocols[0]
    request.log_error("websockify: ws_protocol = '%s' (%s)" % (request.ws_protocol, request.ws_requested_protocols), apache.APLOG_DEBUG)
    pass  # Always accept.

def web_socket_transfer_data(request):
    args_parsed = parse_qs(request.args, False, True)

    target_port = list_value(args_parsed, 'port')[0]
    target_host = list_value(args_parsed, 'host', def_val=['localhost'])[0]

    target = connect(target_host, target_port)

    request.log_error("websockify: %s:%s connected" % (target_host,target_port), apache.APLOG_INFO)

    try:
        do_proxy("%s:%s" % (target_host, target_port), request, target)
    except:
        if target:
            target.shutdown(socket.SHUT_RDWR)
            target.close()
        raise

def do_proxy(sock_name, request, target):
    buffer_size = 65536

    def read_message(message):
        buf  = b64decode(message)
        request.log_error("websockify: %s %d (%d decoded) bytes come from client" % (sock_name, len(message), len(buf)), apache.APLOG_DEBUG)
        sent = 0
        while (sent < len(buf)):
            sent += target.send(buf[sent:])
            request.log_error("websockify: %s %d of %d bytes passed to backend" % (sock_name, sent, len(buf)), apache.APLOG_DEBUG)

    receiver = msgutil.MessageReceiver(request, read_message)

    while True:
        message = target.recv(buffer_size)
        if len(message) == 0:
            raise socket.error('websockify: %s backend connection closed unexpectedly' % (sock_name))
        buf = b64encode(message)
        request.ws_stream.send_message(buf, binary=False)
        request.log_error("websockify: %s %d (%d encoded) bytes passed to client" % (sock_name, len(message), len(buf)), apache.APLOG_DEBUG)

def connect(host, port):
    try:
        return socket.create_connection((socket.gethostbyname(host), port))
    except:
        raise socket.error("websockify: can not connect to '%s:%s': %s" % (host, port, exc_info()[1]))

# vi:sts=4 sw=4 et

from websockify.

kanaka avatar kanaka commented on May 29, 2024

@onokonem. There are a couple of ways to post code like this. If you are wanting for changes to get back into a project, then github makes it trivial to fork the project, add the code and then issue a pull request back to the original project.

Alternately, github provides a gist mechanism for posting single files and examples: gist.github.com which you can then link.

And lastly, you can just put them in a comment with proper formatting (which you have done).

Anyways, I really like the idea of making a modpython+pywebsocket version of websockify. Your code is simple and clean and I would like to pull a version of this into websockify.

However, the I can't accept this change as is because the generic host and port mechanism poses a huge security risk. I discuss this issue here:
novnc/noVNC#49 (comment)

One common way that people have used to solve the "arbitrary target" issue is to pass a token in the query args that is used to lookup the host and port target from a limited list of options.

So the change I would suggest is that when a new connection is made, a configuration file is read that contains a mapping of tokens to host/port targets. Something like this in /etc/websockify:

default = localhost:5900
my_desktop = localhost:5900
my_media_server = joel-media:5900
my_windows_system = joel-win:5901

The websockify path would then include something like "...?target=my_desktop". In the above example, default would be the target that would be used if no "target" is specified in the query parameters. I think loading the config file on every connection would probably be the best option, that way a new target can be added without restarting the web server.

I have considered adding support for this to the standard websockify. If you do this for the mod_python/pywebsocket version then I might be motivated to make this a more standard convention for websockify.

Thanks for your work on this.

from websockify.

onokonem avatar onokonem commented on May 29, 2024

Hi,

yes you right about security risk.

This code is a part of some bigger work, which will include authentication and authorization. This is why I did not think about security too much.

So, conf file looks like a good solution. I'll post new code in a couple of days.

from websockify.

onokonem avatar onokonem commented on May 29, 2024
# websockify proxy to serve noVNC (http://kanaka.github.com/noVNC/)
# with Apache + mod_python + pywebsocket
# Inspired by websockify project (https://github.com/kanaka/websockify)
#
# Supports noVNC path feature
# but in different way than original websockify do:
# GET parameter have to be specified
# like http://your.host.dom/vnc/ws/websockify?host=hostName
#
# hostName must be defined in the vncHosts file (see below)
#
# Install
# 1) Install Apache 2.2 (http://httpd.apache.org/) with mod_python
# 2) Install pywebsocket (http://code.google.com/p/pywebsocket/)
# 3) Place websockify_wsh.py somewhere. Say, /var/www/vnc/ws/websockify_wsh.py
# 4) Configure apache:
#   PythonOption mod_pywebsocket.handler_root /var/www/vnc
#   PythonOption mod_pywebsocket.handler_scan /var/www/vnc/ws
#   # Note: 'PythonOption mod_pywebsocket.handler_*' lines have to be placed
#   #  in the global Apache config scope
#   # (see http://www.mailinglistarchive.com/html/[email protected]/2006-09/msg00720.html)
#   
#   <Location /vnc/ws>
#     PythonOption websockify.vncHosts /etc/vncHosts
#
#     PythonHeaderParserHandler mod_pywebsocket.headerparserhandler
#     PythonDebug On
#   </Location>
# 5) Create vncHosts file:
#   [vncHosts] # Just to satisfy Python ConfigParser
#   hostName1 = ipOrName1:portNumber1
#   hostName2 = ipOrName2:portNumber2
#   ...
#
# Created by Daniel Podolsky, [email protected], 22 Nov 2011

import socket
import ConfigParser

from sys             import exc_info
from urlparse        import parse_qs
from base64          import b64encode, b64decode
from mod_python      import apache
from mod_pywebsocket import msgutil, handshake

def list_value(array, key, def_val=None):
    if key in array:
        return array[key]
    if def_val is not None:
        return def_val
    raise ValueError("key '%s' is not specified" % (key))

def web_socket_do_extra_handshake(request):
    try:
      request.add_common_vars()

      request.subprocess_env['vncHostName'] = list_value(parse_qs(request.args, False, True), 'host')[0]

      config = ConfigParser.ConfigParser()
      config.read(list_value(request.get_options(), 'websockify.vncHosts'))

      vncHost = config.get('vncHosts', request.subprocess_env['vncHostName']).split(':', 2)

      request.subprocess_env['vncHostAddr'] = vncHost[0]
      request.subprocess_env['vncHostPort'] = vncHost[1]
    except:
      raise handshake.AbortedByUserException("websockify: connection denied: %s" % (exc_info()[1]))

    request.ws_protocol = request.ws_requested_protocols[0]
    request.log_error("websockify: ws_protocol = '%s' (%s)" % (request.ws_protocol, request.ws_requested_protocols), apache.APLOG_INFO)

    pass  # Always accept.

def web_socket_transfer_data(request):
    target = connect(request.subprocess_env['vncHostAddr'], request.subprocess_env['vncHostPort'])

    sockName = "%s(%s:%s)" % (request.subprocess_env['vncHostName'],
                              request.subprocess_env['vncHostAddr'],
                              request.subprocess_env['vncHostPort']
                             )

    request.log_error("websockify: %s connected" % (sockName), apache.APLOG_NOTICE)

    try:
      do_proxy(sockName, request, target)
    except:
      if target:
        target.shutdown(socket.SHUT_RDWR)
        target.close()
      raise

def do_proxy(sock_name, request, target):
    buffer_size = 65536

    def read_message(message):
        buf  = b64decode(message)
        request.log_error("websockify: %s %d (%d decoded) bytes come from client" % (sock_name, len(message), len(buf)), apache.APLOG_DEBUG)
        sent = 0
        while (sent < len(buf)):
          sent += target.send(buf[sent:])
          request.log_error("websockify: %s %d of %d bytes passed to backend" % (sock_name, sent, len(buf)), apache.APLOG_DEBUG)

    receiver = msgutil.MessageReceiver(request, read_message)

    while True:
      message = target.recv(buffer_size)
      if len(message) == 0:
        raise socket.error('websockify: %s backend connection closed unexpectedly' % (sock_name))
      buf = b64encode(message)
      request.ws_stream.send_message(buf, binary=False)
      request.log_error("websockify: %s %d (%d encoded) bytes passed to client" % (sock_name, len(message), len(buf)), apache.APLOG_DEBUG)

def connect(host, port):
    try:
      return socket.create_connection((socket.gethostbyname(host), port))
    except:
      raise socket.error("websockify: can not connect to '%s:%s': %s" % (host, port, exc_info()[1]))

# vi:sts=4 sw=4 et

from websockify.

rakesh-roshan avatar rakesh-roshan commented on May 29, 2024

Where to put the javascript files, and do we need to make changes in any of those javascript files?

from websockify.

onokonem avatar onokonem commented on May 29, 2024

anywhere you like :) and no you do not need to modify js

from websockify.

rakesh-roshan avatar rakesh-roshan commented on May 29, 2024

But you have written that the

GET parameters have to be specified

like http://your.host.dom/vnc/ws/websockify?host=localhost&port=5900

or just http://your.host.dom/vnc/ws/websockify?port=5900

But the javascript provided gives GET parameter as websockify only.
I am not able to understand that where we have to tell the javascript to connect to apache server rather than the old websockify proxy server? Should I write in the connection parameter on vnc.html as apache_server_address and in port as port 80?

from websockify.

rakesh-roshan avatar rakesh-roshan commented on May 29, 2024

As per the apache config,

#  <Location /vnc/ws>
#     PythonOption websockify.vncHosts /etc/vncHosts
#
#     PythonHeaderParserHandler mod_pywebsocket.headerparserhandler
#     PythonDebug On
#   </Location>

I understand that the PythonHandler is used when the path matches /vnc/ws, but without modifying js, how can we do this?

I put javascripts and vnc.html in var/www folder. If I use apache server address as the connection parameter on vnc.html and tries to connect it gives the error,

[Wed Mar 28 11:24:08 2012] [error] [client 127.0.0.1] File does not exist: /var/www/websockify

from websockify.

onokonem avatar onokonem commented on May 29, 2024

Look at http://kanaka.github.com/noVNC/noVNC/vnc.html.

Under the Settings button you should see a menu with path field.

from websockify.

rakesh-roshan avatar rakesh-roshan commented on May 29, 2024

I gave vnc/ws/websockify in the path field and host as localhost and port 80(for my apache server) and VNC password. I places websockify_wsh.py in the directory /var/www/vnc/ws. I am getting error

[Wed Mar 28 15:03:45 2012] [info] mod_pywebsocket.headerparserhandler: Initializing Dispatcher
[Wed Mar 28 15:03:45 2012] [error] [client 127.0.0.1] File does not exist: /var/www/vnc/ws/websockify
~

Am I doing something wrong?

from websockify.

ulrichSchreiner avatar ulrichSchreiner commented on May 29, 2024

Hi,

the script works fine, but in the function "web_socket_do_extra_handshake" i had to insert an "if":

if request.ws_requested_protocols is not None:
  request.ws_protocol = request.ws_requested_protocols[0]

in the documentation of pywebsockets you can read this:

For HyBi 06 and later, ws_protocol is always set to None when
web_socket_do_extra_handshake is called. If ws_requested_protocols is not
None, you must choose one subprotocol from this list and set it to
ws_protocol.

And if you use pywebsockets and this script you should play with the apache-settings, for the request-timeouts, otherwise your connection will be killed after some time. Look at the apache-Module (http://httpd.apache.org/docs/trunk/mod/mod_reqtimeout.html).

For simple tests you can use:

RequestReadTimeout header=60,MinRate=1 body=60,MinRate=1

But be careful with this!

from websockify.

rakesh-roshan avatar rakesh-roshan commented on May 29, 2024

Hi ,

Thanks adding that support for old websocket protocol solved my problem :)

Thanks a lot,

Rakesh Roshan

On Sat, Apr 14, 2012 at 7:47 AM, ulrichSchreiner <
[email protected]

wrote:

Hi,

the script works fine, but in the function "web_socket_do_extra_handshake"
i had to insert an "if":

if request.ws_requested_protocols is not None:
request.ws_protocol = request.ws_requested_protocols[0]

in the documentation of pywebsockets you can read this:

For HyBi 06 and later, ws_protocol is always set to None when
web_socket_do_extra_handshake is called. If ws_requested_protocols is not
None, you must choose one subprotocol from this list and set it to
ws_protocol.

And if you use pywebsockets and this script you should play with the
apache-settings, for the request-timeouts, otherwise your connection will
be killed after some time. Look at the apache-Module (
http://httpd.apache.org/docs/trunk/mod/mod_reqtimeout.html).

For simple tests you can use:

RequestReadTimeout header=60,MinRate=1 body=60,MinRate=1

But be careful with this!


Reply to this email directly or view it on GitHub:
#19 (comment)

from websockify.

denpiepe avatar denpiepe commented on May 29, 2024

I’ve more details now.
fact is, the websocket-handshake is OK and run. after the ws-handshake the noVNC Page receive the message from the pywebsockify handler, but there is no answer from the page. I guess there are two possibilities: 1. the web-page receive the b64 text "RFB 003.008\n" but can't decode it, or 2. the web-page receives and decode the VNC-Handshake but sends no answer to the ws-server/gateway.

can someone tell me, how I can check this possibilities? the rQ-message in util.js is empty, but the recv_message Data is OK. in the recv_message is the b64 encoded "RBF 003.008\n"

is it possible to turn the b64 function in this websockify_wsh handler off and use binary only?

from websockify.

denpiepe avatar denpiepe commented on May 29, 2024

ok, i've solved the problem. it was the encode/decode with b64. without the b64 coding, it works fine.

my next problem is, i want to split the server into a server an a second client. first the websockify-server should run on the apache2 with the mod_python handler but don't connect to the local port 5900. it should work as "server in the middle" and serve a websocket-connection to a second client too. the second client (pyhton) should connect to the websockify-server an bridge the traffic to the local port 5900.

can anyone help me for the second client? i want to implement it in python.

it should be like the following image
oma_rc_websocket_github

from websockify.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.