Send seq nums and b64 encode based on query string.

Query string variable 'b64encode' determine if wsproxy b64 encodes the
results. Variable 'seq_num' determines if sequence numbers are
prepended. This way, sequence numbers are only used with the flash
WebSocket proxy.
This commit is contained in:
Joel Martin 2010-04-18 20:35:43 -05:00
parent 8759ea6f90
commit 07287cfd89
3 changed files with 118 additions and 86 deletions

View File

@ -65,7 +65,7 @@
RFB.updateState('failed', "'file://' URL is incompatible with Adobe Flash"); RFB.updateState('failed', "'file://' URL is incompatible with Adobe Flash");
} else { } else {
WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf"; WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf";
RFB.force_copy = true; RFB.use_seq = true;
RFB.updateState('disconnected', 'Disconnected'); RFB.updateState('disconnected', 'Disconnected');
} }
} }

154
vnc.js
View File

@ -83,7 +83,7 @@ RFB = {
ws : null, // Web Socket object ws : null, // Web Socket object
sendID : null, sendID : null,
force_copy : false, use_seq : false,
version : "RFB 003.003\n", version : "RFB 003.003\n",
state : 'disconnected', state : 'disconnected',
@ -647,6 +647,84 @@ clientCutText: function (text) {
* Utility routines * Utility routines
*/ */
recv_message: function(e) {
//console.log(">> recv_message");
RQ = RQ.concat(Base64.decode(e.data, 0));
RFB.handle_message();
//console.log("<< recv_message");
},
recv_message_reorder: function(e) {
//console.log(">> recv_message_reorder");
var offset = e.data.indexOf(":") + 1;
var seq_num = parseInt(e.data.substr(0, offset-1));
if (RQ_seq_num == seq_num) {
RQ = RQ.concat(Base64.decode(e.data, offset));
RQ_seq_num++;
} else {
console.warn("sequence number mismatch RQ_seq_num:" + RQ_seq_num + ", seq_num:" + seq_num);
if (RQ_reorder.length > 20) {
RFB.updateState('failed', "Re-order queue too long");
} else {
RQ_reorder = RQ_reorder.concat(e.data.substr(0));
var i = 0;
while (i < RQ_reorder.length) {
var offset = RQ_reorder[i].indexOf(":") + 1;
var seq_num = parseInt(RQ_reorder[i].substr(0, offset-1));
console.log("Searching reorder list item " + i + ", seq_num " + seq_num);
if (seq_num == RQ_seq_num) {
/* Remove it from reorder queue, decode it and
* add it to the receive queue */
console.log("Found re-ordered packet seq_num " + seq_num);
RQ = RQ.concat(Base64.decode(RQ_reorder.splice(i, 1)[0], offset));
RQ_seq_num++;
i = 0; // Start search again for next one
} else {
i++;
}
}
}
}
RFB.handle_message();
//console.log("<< recv_message_reorder");
},
handle_message: function () {
switch (RFB.state) {
case 'disconnected':
console.error("Got data while disconnected");
break;
case 'reset':
/* close and reset connection */
RFB.disconnect();
RFB.init_ws();
break;
case 'failed':
console.log("Giving up!");
RFB.disconnect();
break;
case 'normal':
RFB.normal_msg();
/*
while (RQ.length > 0) {
if (RFB.normal_msg() && RFB.state == 'normal') {
console.log("More to process");
} else {
break;
}
}
*/
break;
default:
RFB.init_msg();
break;
}
},
send_string: function (str) { send_string: function (str) {
//console.log(">> send_string: " + str); //console.log(">> send_string: " + str);
RFB.send_array(str.split('').map( RFB.send_array(str.split('').map(
@ -828,74 +906,18 @@ updateState: function(state, statusMsg) {
init_ws: function () { init_ws: function () {
console.log(">> init_ws"); console.log(">> init_ws");
var uri = "ws://" + RFB.host + ":" + RFB.port; var uri = "ws://" + RFB.host + ":" + RFB.port + "/?b64encode";
if (RFB.use_seq) {
uri += "&seq_num";
}
console.log("connecting to " + uri); console.log("connecting to " + uri);
RFB.ws = new WebSocket(uri); RFB.ws = new WebSocket(uri);
RFB.ws.onmessage = function(e) {
//console.log(">> WebSocket.onmessage");
var offset = e.data.indexOf(":") + 1; if (RFB.use_seq) {
var seq_num = parseInt(e.data.substr(0, offset-1)); RFB.ws.onmessage = RFB.recv_message_reorder;
if (RQ_seq_num == seq_num) { } else {
RQ = RQ.concat(Base64.decode(e.data, offset)); RFB.ws.onmessage = RFB.recv_message;
RQ_seq_num++; }
} else {
console.warn("sequence number mismatch RQ_seq_num:" + RQ_seq_num + ", seq_num:" + seq_num);
if (RQ_reorder.length > 20) {
RFB.updateState('failed', "Re-order queue too long");
} else {
RQ_reorder = RQ_reorder.concat(e.data.substr(0));
var i = 0;
while (i < RQ_reorder.length) {
var offset = RQ_reorder[i].indexOf(":") + 1;
var seq_num = parseInt(RQ_reorder[i].substr(0, offset-1));
console.log("Searching reorder list item " + i + ", seq_num " + seq_num);
if (seq_num == RQ_seq_num) {
/* Remove it from reorder queue, decode it and
* add it to the receive queue */
console.log("Found re-ordered packet seq_num " + seq_num);
RQ = RQ.concat(Base64.decode(RQ_reorder.splice(i, 1)[0], offset));
RQ_seq_num++;
i = 0; // Start search again for next one
} else {
i++;
}
}
}
}
switch (RFB.state) {
case 'disconnected':
console.error("WebSocket.onmessage while disconnected");
break;
case 'reset':
/* close and reset connection */
RFB.disconnect();
RFB.init_ws();
break;
case 'failed':
console.log("Giving up!");
RFB.disconnect();
break;
case 'normal':
RFB.normal_msg();
/*
while (RQ.length > 0) {
if (RFB.normal_msg() && RFB.state == 'normal') {
console.log("More to process");
} else {
break;
}
}
*/
break;
default:
RFB.init_msg();
break;
}
//console.log("<< WebSocket.onmessage");
};
RFB.ws.onopen = function(e) { RFB.ws.onopen = function(e) {
console.log(">> WebSocket.onopen"); console.log(">> WebSocket.onopen");
RFB.updateState('ProtocolVersion', "Starting VNC handshake"); RFB.updateState('ProtocolVersion', "Starting VNC handshake");

View File

@ -1,11 +1,12 @@
#!/usr/bin/python #!/usr/bin/python
import sys, os, socket, time, traceback import sys, os, socket, time, traceback, re
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from select import select from select import select
buffer_size = 65536 buffer_size = 65536
send_seq = 0 send_seq = 0
client_settings = {}
server_handshake = """HTTP/1.1 101 Web Socket Protocol Handshake\r server_handshake = """HTTP/1.1 101 Web Socket Protocol Handshake\r
Upgrade: WebSocket\r Upgrade: WebSocket\r
@ -32,21 +33,27 @@ Traffic Legend:
def do_handshake(client): def do_handshake(client):
global client_settings
handshake = client.recv(1024) handshake = client.recv(1024)
print "Handshake [%s]" % handshake #print "Handshake [%s]" % handshake
if handshake.startswith("<policy-file-request/>"): if handshake.startswith("<policy-file-request/>"):
print "Sending:", policy_response print "Sending flash policy response"
client.send(policy_response) client.send(policy_response)
client.close() client.close()
return False return False
#handshake = client.recv(1024)
#if len(handshake) == 0:
# raise Exception("Policy exchange failed")
#print "Handshake [%s]" % handshake
req_lines = handshake.split("\r\n") req_lines = handshake.split("\r\n")
_, path, _ = req_lines[0].split(" ") _, path, _ = req_lines[0].split(" ")
_, origin = req_lines[4].split(" ") _, origin = req_lines[4].split(" ")
_, host = req_lines[3].split(" ") _, host = req_lines[3].split(" ")
# Parse settings from the path
cvars = path.partition('?')[2].partition('#')[0].split('&')
for cvar in [c for c in cvars if c]:
name, _, value = cvar.partition('=')
client_settings[name] = value and value or True
print "client_settings:", client_settings
client.send(server_handshake % (origin, host, path)) client.send(server_handshake % (origin, host, path))
return True return True
@ -76,7 +83,7 @@ def proxy(client, target):
if tqueue and target in outs: if tqueue and target in outs:
#print "Target send: %s" % repr(tqueue[0]) #print "Target send: %s" % repr(tqueue[0])
log.write("Target send: %s\n" % map(ord, tqueue[0])) ##log.write("Target send: %s\n" % map(ord, tqueue[0]))
dat = tqueue.pop(0) dat = tqueue.pop(0)
sent = target.send(dat) sent = target.send(dat)
if sent == len(dat): if sent == len(dat):
@ -90,25 +97,28 @@ def proxy(client, target):
sent = client.send(dat) sent = client.send(dat)
if sent == len(dat): if sent == len(dat):
traffic("<") traffic("<")
log.write("Client send: %s\n" % repr(dat)) ##log.write("Client send: %s\n" % repr(dat))
else: else:
cqueue.insert(0, dat[sent:]) cqueue.insert(0, dat[sent:])
traffic("<.") traffic("<.")
log.write("Client send partial: %s\n" % repr(dat[0:send])) ##log.write("Client send partial: %s\n" % repr(dat[0:send]))
if target in ins: if target in ins:
buf = target.recv(buffer_size) buf = target.recv(buffer_size)
if len(buf) == 0: raise Exception("Target closed") if len(buf) == 0: raise Exception("Target closed")
#enc = b64encode(buf) ##log.write("Target recv (%d): %s\n" % (len(buf), map(ord, buf)))
#chksum = sum([ord(c) for c in enc])
#cqueue.append("\x00^" + str(chksum) + "@" + enc + "$\xff")
cqueue.append("\x00%d:%s\xff" % (send_seq, b64encode(buf))) if client_settings.get("b64encode"):
send_seq += 1 buf = b64encode(buf)
if client_settings.get("seq_num"):
cqueue.append("\x00%d:%s\xff" % (send_seq, buf))
send_seq += 1
else:
cqueue.append("\x00%s\xff" % buf)
log.write("Target recv (%d): %s\n" % (len(buf), map(ord, buf)))
traffic("{") traffic("{")
if client in ins: if client in ins:
@ -117,7 +127,7 @@ def proxy(client, target):
if buf[-1] == "\xff": if buf[-1] == "\xff":
traffic("}") traffic("}")
log.write("Client recv (%d): %s\n" % (len(buf), repr(buf))) ##log.write("Client recv (%d): %s\n" % (len(buf), repr(buf)))
if cpartial: if cpartial:
tqueue.extend(decode(cpartial + buf)) tqueue.extend(decode(cpartial + buf))
cpartial = "" cpartial = ""
@ -125,7 +135,7 @@ def proxy(client, target):
tqueue.extend(decode(buf)) tqueue.extend(decode(buf))
else: else:
traffic("}.") traffic("}.")
log.write("Client recv partial (%d): %s\n" % (len(buf), repr(buf))) ##log.write("Client recv partial (%d): %s\n" % (len(buf), repr(buf)))
cpartial = cpartial + buf cpartial = cpartial + buf
@ -157,7 +167,7 @@ def start_server(listen_port, target_host, target_port):
if tsock: tsock.close() if tsock: tsock.close()
if __name__ == '__main__': if __name__ == '__main__':
log = open("ws.log", 'w') ##log = open("ws.log", 'w')
try: try:
if len(sys.argv) != 4: raise if len(sys.argv) != 4: raise
listen_port = int(sys.argv[1]) listen_port = int(sys.argv[1])