Files
noVNC/utils/wsproxy.py
Joel Martin 31407abc25 Issue #11: daemonize after opening listen port.
The listen port should be opened before daemonizing otherwise if
opening the port fails, the user will get no feedback. The only
complication was that the listen socket needs to not be closed as part
of daemonizing.

Thanks to http://github.com/rickr for finding it.
2010-07-17 12:05:58 -05:00

161 lines
5.1 KiB
Python
Executable File

#!/usr/bin/python
'''
A WebSocket to TCP socket proxy with support for "wss://" encryption.
Copyright 2010 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
'''
import sys, socket, ssl, optparse
from select import select
from websocket import *
buffer_size = 65536
rec = None
traffic_legend = """
Traffic Legend:
} - Client receive
}. - Client receive partial
{ - Target receive
> - Target send
>. - Target send partial
< - Client send
<. - Client send partial
"""
def do_proxy(client, target):
""" Proxy WebSocket to normal socket. """
global rec
cqueue = []
cpartial = ""
tqueue = []
rlist = [client, target]
while True:
wlist = []
if tqueue: wlist.append(target)
if cqueue: wlist.append(client)
ins, outs, excepts = select(rlist, wlist, [], 1)
if excepts: raise Exception("Socket exception")
if target in outs:
dat = tqueue.pop(0)
sent = target.send(dat)
if sent == len(dat):
traffic(">")
else:
tqueue.insert(0, dat[sent:])
traffic(".>")
##if rec: rec.write("Target send: %s\n" % map(ord, dat))
if client in outs:
dat = cqueue.pop(0)
sent = client.send(dat)
if sent == len(dat):
traffic("<")
##if rec: rec.write("Client send: %s ...\n" % repr(dat[0:80]))
if rec: rec.write("%s,\n" % repr(">" + dat[1:-1]))
else:
cqueue.insert(0, dat[sent:])
traffic("<.")
##if rec: rec.write("Client send partial: %s\n" % repr(dat[0:send]))
if target in ins:
buf = target.recv(buffer_size)
if len(buf) == 0: raise Exception("Target closed")
cqueue.append(encode(buf))
traffic("{")
##if rec: rec.write("Target recv (%d): %s\n" % (len(buf), map(ord, buf)))
if client in ins:
buf = client.recv(buffer_size)
if len(buf) == 0: raise Exception("Client closed")
if buf[-1] == '\xff':
if buf.count('\xff') > 1:
traffic(str(buf.count('\xff')))
traffic("}")
##if rec: rec.write("Client recv (%d): %s\n" % (len(buf), repr(buf)))
if rec: rec.write("%s,\n" % repr(buf[1:-1]))
if cpartial:
tqueue.extend(decode(cpartial + buf))
cpartial = ""
else:
tqueue.extend(decode(buf))
else:
traffic(".}")
##if rec: rec.write("Client recv partial (%d): %s\n" % (len(buf), repr(buf)))
cpartial = cpartial + buf
def proxy_handler(client):
global target_host, target_port, options, rec
if settings['record']:
print "Opening record file: %s" % settings['record']
rec = open(settings['record'], 'a')
print "Connecting to: %s:%s" % (target_host, target_port)
tsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tsock.connect((target_host, target_port))
print traffic_legend
try:
do_proxy(client, tsock)
except:
if tsock: tsock.close()
if rec: rec.close()
raise
if __name__ == '__main__':
usage = "%prog [--record FILE]"
usage += " [source_addr:]source_port target_addr:target_port"
parser = optparse.OptionParser(usage=usage)
parser.add_option("--record",
help="record session to a file", metavar="FILE")
parser.add_option("--foreground", "-f",
dest="daemon", default=True, action="store_false",
help="stay in foreground, do not daemonize")
parser.add_option("--ssl-only", action="store_true",
help="disallow non-encrypted connections")
parser.add_option("--cert", default="self.pem",
help="SSL certificate")
(options, args) = parser.parse_args()
if len(args) > 2: parser.error("Too many arguments")
if len(args) < 2: parser.error("Too few arguments")
if args[0].count(':') > 0:
host,port = args[0].split(':')
else:
host,port = '',args[0]
if args[1].count(':') > 0:
target_host,target_port = args[1].split(':')
else:
parser.error("Error parsing target")
try: port = int(port)
except: parser.error("Error parsing listen port")
try: target_port = int(target_port)
except: parser.error("Error parsing target port")
if options.ssl_only and not os.path.exists(options.cert):
parser.error("SSL only and %s not found" % options.cert)
settings['listen_host'] = host
settings['listen_port'] = port
settings['handler'] = proxy_handler
settings['cert'] = os.path.abspath(options.cert)
settings['ssl_only'] = options.ssl_only
settings['daemon'] = options.daemon
if options.record:
settings['record'] = os.path.abspath(options.record)
start_server()