-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcontrol.py
97 lines (77 loc) · 3.04 KB
/
control.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from json import loads
from twisted.internet import reactor
from twisted.internet.error import CannotListenError
from twisted.internet.protocol import ServerFactory
from twisted.internet.ssl import DefaultOpenSSLContextFactory
from twisted.protocols.basic import LineReceiver
from twisted.python import log
from txws import WebSocketFactory
from vncap.vnc.factory import VNCProxy
# Allowed proxy port ranges.
# By default, this is the VNC port range.
# To use a different port range, simply change the following two lines.
FIRST_PORT = 5800
LAST_PORT = 5900
class ControlProtocol(LineReceiver):
def lineReceived(self, line):
log.msg("Received line %s" % line)
try:
d = loads(line)
# Required names.
host = d["daddr"]
dport = d["dport"]
password = d["password"]
# Optional names.
sport = d.get("sport")
ws = d.get("ws", False)
tls = d.get("tls", False)
client_opts = d.get("client", {})
timeout_secs = d.get("timeout", 30)
# Allocate the source port.
sport = self.factory.allocate_port(sport)
factory = VNCProxy(host, dport, password, client_opts)
if ws:
factory = WebSocketFactory(factory)
if tls:
context = DefaultOpenSSLContextFactory("keys/vncap.key",
"keys/vncap.crt")
listening = reactor.listenSSL(sport, factory, context)
else:
listening = reactor.listenTCP(sport, factory)
# Set up our timeout.
def timeout():
log.msg("Timed out connection on port %d" % sport)
listening.stopListening()
self.factory.free_port(sport)
reactor.callLater(timeout_secs, timeout)
log.msg("New forwarder (%d->%s:%d)" % (sport, host, dport))
self.sendLine("%d" % sport)
except (KeyError, ValueError):
log.msg("Couldn't handle line %s" % line)
self.sendLine("FAILED")
except CannotListenError:
# Couldn't bind the port. Don't free it, as it's probably not
# available to us.
log.msg("Couldn't bind port %d" % sport)
self.sendLine("FAILED")
self.transport.loseConnection()
class ControlFactory(ServerFactory):
protocol = ControlProtocol
def __init__(self):
self.pool = set(range(FIRST_PORT, LAST_PORT))
def allocate_port(self, port=None):
"""
Allocate a port.
If a specific port is requested, try to allocate that port. A random
port will be selected if it is not available. A random port will also
be selected if no specific port is requested.
"""
if port not in self.pool:
port = self.pool.pop()
self.pool.discard(port)
return port
def free_port(self, port):
"""
Free a port for further allocations.
"""
self.pool.add(port)