diff --git a/rfb_notes b/rfb_notes new file mode 100644 index 00000000..643e16c0 --- /dev/null +++ b/rfb_notes @@ -0,0 +1,147 @@ +5.1.1 ProtocolVersion: 12, 12 bytes + + - Sent by server, max supported + 12 ascii - "RFB 003.008\n" + - Response by client, version to use + 12 ascii - "RFB 003.003\n" + +5.1.2 Authentication: >=4, [16, 4] bytes + + - Sent by server + CARD32 - authentication-scheme + 0 - connection failed + CARD32 - length + length - reason + 1 - no authentication + + 2 - VNC authentication + 16 CARD8 - challenge (random bytes) + + - Response by client (if VNC authentication) + 16 CARD8 - client encrypts the challenge with DES, using user + password as key, sends resulting 16 byte response + + - Response by server (if VNC authentication) + CARD32 - 0 - OK + 1 - failed + 2 - too-many + +5.1.3 ClientInitialisation: 1 byte + - Sent by client + CARD8 - shared-flag, 0 exclusive, non-zero shared + +5.1.4 ServerInitialisation: >=24 bytes + - Sent by server + CARD16 - framebuffer-width + CARD16 - framebuffer-height + 16 byte PIXEL_FORMAT - server-pixel-format + CARD8 - bits-per-pixel + CARD8 - depth + CARD8 - big-endian-flag, non-zero is big endian + CARD8 - true-color-flag, non-zero then next 6 apply + CARD16 - red-max + CARD16 - green-max + CARD16 - blue-max + CARD8 - red-shift + CARD8 - green-shift + CARD8 - blue-shift + 3 bytes - padding + CARD32 - name-length + + CARD8[length] - name-string + + + +Client to Server Messages: + +5.2.1 SetPixelFormat: 20 bytes + CARD8: 0 - message-type + ... + +5.2.2 FixColourMapEntries: >=6 bytes + CARD8: 1 - message-type + ... + +5.2.3 SetEncodings: >=8 bytes + CARD8: 2 - message-type + CARD8 - padding + CARD16 - numer-of-encodings + + CARD32 - encoding-type in preference order + 0 - raw + 1 - copy-rectangle + 2 - RRE + 4 - CoRRE + 5 - hextile + +5.2.4 FramebufferUpdateRequest (10 bytes) + CARD8: 3 - message-type + CARD8 - incremental (0 for full-update, non-zero for incremental) + CARD16 - x-position + CARD16 - y-position + CARD16 - width + CARD16 - height + + +5.2.5 KeyEvent: 8 bytes + CARD8: 4 - message-type + CARD8 - down-flag + 2 bytes - padding + CARD32 - key (X-Windows keysym values) + +5.2.6 PointerEvent: 6 bytes + CARD8: 5 - message-type + CARD8 - button-mask + CARD16 - x-position + CARD16 - y-position + +5.2.7 ClientCutText: >=9 bytes + CARD8: 6 - message-type + ... + + +Server to Client Messages: + +5.3.1 FramebufferUpdate + CARD8: 0 - message-type + 1 byte - padding + CARD16 - number-of-rectangles + + CARD16 - x-position + CARD16 - y-position + CARD16 - width + CARD16 - height + CARD16 - encoding-type: + 0 - raw + 1 - copy rectangle + 2 - RRE + 4 - CoRRE + 5 - hextile + + raw: + - width x height pixel values + + copy rectangle: + CARD16 - src-x-position + CARD16 - src-y-position + + RRE: + CARD32 - N number-of-subrectangles + Nxd bytes - background-pixel-value (d bits-per-pixel) + + ... + +5.3.2 SetColourMapEntries (no support) + CARD8: 1 - message-type + ... + +5.3.3 Bell + CARD8: 2 - message-type + +5.3.4 ServerCutText + CARD8: 3 - message-type + + + + + diff --git a/vnc.html b/vnc.html new file mode 100644 index 00000000..196e4183 --- /dev/null +++ b/vnc.html @@ -0,0 +1,38 @@ + + + + + VNC Window:
+ + + Canvas not supported. + + +

+ Debug: +
+ + + + + + + + + + diff --git a/vnc.js b/vnc.js new file mode 100644 index 00000000..7a565aba --- /dev/null +++ b/vnc.js @@ -0,0 +1,339 @@ +debug("here0"); +var ws = null; +var vnc_host = ''; +var vnc_port = 5900; +var rfb_state = 'ProtocolVersion'; +var rfb_shared = 1; +var fb_width = 0; +var fb_height = 0; +var fb_name = ""; + +function card8(num) { + return String.fromCharCode(num); +} +String.prototype.card8 = function (pos) { + return this.charCodeAt(pos); +} + +function card16(num) { + return String.fromCharCode(num >> 8) + + String.fromCharCode(num & 0xFF); +} +String.prototype.card16 = function (pos) { + debug("card16 0: " + this.charCodeAt(pos)); + debug("card16 1: " + this.charCodeAt(pos+1)); + return (this.charCodeAt(pos) << 8) + + (this.charCodeAt(pos+1) ); +} + +function card32(num) { + return String.fromCharCode( num >> 24) + + String.fromCharCode((num >> 16) & 0xFF) + + String.fromCharCode((num >> 8) & 0xFF) + + String.fromCharCode( num & 0xFF); +} +String.prototype.card32 = function (pos) { + debug("card32 0: " + this.charCodeAt(pos)); + debug("card32 1: " + this.charCodeAt(pos+1)); + debug("card32 2: " + this.charCodeAt(pos+2)); + debug("card32 3: " + this.charCodeAt(pos+3)); + return (this.charCodeAt(pos) << 24) + + (this.charCodeAt(pos+1) << 16) + + (this.charCodeAt(pos+2) << 8) + + (this.charCodeAt(pos+3) ); +} + +function debug(str) { + cell = $('debug'); + cell.innerHTML += str + "
"; +} + + +/* + * Server message handlers + */ + +/* RFB/VNC initialisation */ +function rfb_init_msg(data) { + debug(">> rfb_init_msg"); + switch (rfb_state) { + + case 'ProtocolVersion' : + debug("ProtocolVersion: " + data) + if (data.length != 12) { + debug("Invalid protocol version from server"); + rfb_state = 'reset'; + return; + } + ws.send("RFB 003.003\n"); + rfb_state = 'Authentication'; + break; + + case 'Authentication' : + debug("Authentication") + if (data.length != 4) { + debug("Invalid auth scheme"); + rfb_state = 'reset'; + return; + } + var scheme = data.card32(0); + debug("Auth scheme: " + scheme); + switch (scheme) { + case 0: // connection failed + var strlen = data.card32(4); + var reason = data.substr(8, strlen); + debug("auth failed: " + reason); + rfb_state = "reset"; + return; + case 1: // no authentication + ws.send(card8(rfb_shared)); // ClientInitialisation + rfb_state = "ServerInitialisation"; + break; + case 2: // VNC authentication + var challenge = data.substr(4, 16); + // TODO: + //var crypt = des(challenge, password); + //ws.send(crypt); + rfb_state = "Authentication-VNC"; + break; + } + break; + + case 'Authentication-VNC' : + debug("Authentication-VNC") + if (data.length != 4) { + debug("Invalid server auth response"); + rfb_state = 'reset'; + return; + } + var resp = data.card32(0); + switch (resp) { + case 0: // OK + debug("Authentication OK"); + break; + case 1: // failed + debug("Authentication failed"); + rfb_state = "reset"; + return; + case 2: // too-many + debug("Too many authentication attempts"); + rfb_state = "reset"; + return; + } + ws.send(card8(rfb_shared)); // ClientInitialisation + rfb_state = "ServerInitialisation"; + break; + + case 'ServerInitialisation' : + debug("ServerInitialisation") + if (data.length < 24) { + debug("Invalid server initialisation"); + rfb_state = 'reset'; + return; + } + fb_width = data.card16(0); + fb_height = data.card16(2); + var name_length = data.card32(20); + fb_name = data.substr(24, name_length); + debug("Screen size: " + fb_width + "x" + fb_height); + debug("Name: " + fb_name); + rfb_state = 'normal'; + break; + } + debug("<< rfb_init_msg"); +} + +/* Normal RFB/VNC messages */ +function rfb_msg(data) { + debug(">> rfb_msg"); + var msg_type = data.card8(0); + switch (msg_type) { + case 0: // FramebufferUpdate + debug("FramebufferUpdate"); + break; + case 1: // SetColourMapEntries + debug("SetColourMapEntries"); + break; + case 2: // Bell + debug("Bell"); + break; + case 3: // ServerCutText + debug("ServerCutText"); + break; + default: + debug("Unknown server message type: " + msg_type); + break; + } + debug("<< rfb_msg"); +} + +/* + * Client message routines + */ + +function setPixelFormat() { +} + +function fixColourMapEntries() { +} + +function setEncodings() { +} + +function fbUpdateRequest() { +} + +function keyEvent() { +} + +function pointerEvent() { +} + +function clientCutText() { +} + + +/* + * Setup routines + */ + +function _init_ws() { + debug(">> _init_ws"); + var uri = "ws://" + vnc_host + ":" + vnc_port; + debug("connecting to " + uri); + ws = new WebSocket(uri); + ws.onmessage = function(e) { + debug(">> onmessage"); + if (rfb_state != 'normal') { + rfb_init_msg(e.data); + } else { + rfb_msg(e.data); + } + if (rfb_state == 'reset') { + /* close and reset connection */ + ws.close(); + _init_ws(); + } + debug("<< onmessage"); + }; + ws.onopen = function(e) { + debug(">> onopen"); + rfb_state = "ProtocolVersion"; + debug("<< onopen"); + }; + ws.onclose = function(e) { + debug(">> onclose"); + rfb_state = "closed"; + debug("<< onclose"); + } + debug("<< _init_ws"); +} + +function init_ws(host, port) { + debug(">> init_ws"); + vnc_host = host; + vnc_port = port; + if (ws) { + ws.close(); + } + _init_ws(); + debug("<< init_ws"); + +} + +/* +function draw() { + var canvas = document.getElementById('vnc'); + + if (! canvas.getContext) return; + + var ctx = canvas.getContext('2d'); + + ctx.fillStyle = "rgb(50,50,50)"; + ctx.fillRect(0, 0, 800, 600); + + var img = new Image(); + img.src = "head_ani2.gif" + + ctx.drawImage(img, 10, 10); + + ctx.drawImage(canvas, 20, 20, 30, 30, 70, 70, 30, 30); +} + + +function draw2() { + var canvas = document.getElementById('tutorial'); + + if (! canvas.getContext) return; + + var ctx = canvas.getContext('2d'); + + roundedRect(ctx,12,12,150,150,15); + roundedRect(ctx,19,19,150,150,9); + roundedRect(ctx,53,53,49,33,10); + roundedRect(ctx,53,119,49,16,6); + roundedRect(ctx,135,53,49,33,10); + roundedRect(ctx,135,119,25,49,10); + + ctx.beginPath(); + ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,true); + ctx.lineTo(31,37); + ctx.fill(); + for(var i=0;i<8;i++){ + ctx.fillRect(51+i*16,35,4,4); + } + for(i=0;i<6;i++){ + ctx.fillRect(115,51+i*16,4,4); + } + for(i=0;i<8;i++){ + ctx.fillRect(51+i*16,99,4,4); + } + ctx.beginPath(); + ctx.moveTo(83,116); + ctx.lineTo(83,102); + ctx.bezierCurveTo(83,94,89,88,97,88); + ctx.bezierCurveTo(105,88,111,94,111,102); + ctx.lineTo(111,116); + ctx.lineTo(106.333,111.333); + ctx.lineTo(101.666,116); + ctx.lineTo(97,111.333); + ctx.lineTo(92.333,116); + ctx.lineTo(87.666,111.333); + ctx.lineTo(83,116); + ctx.fill(); + ctx.fillStyle = "white"; + ctx.beginPath(); + ctx.moveTo(91,96); + ctx.bezierCurveTo(88,96,87,99,87,101); + ctx.bezierCurveTo(87,103,88,106,91,106); + ctx.bezierCurveTo(94,106,95,103,95,101); + ctx.bezierCurveTo(95,99,94,96,91,96); + ctx.moveTo(103,96); + ctx.bezierCurveTo(100,96,99,99,99,101); + ctx.bezierCurveTo(99,103,100,106,103,106); + ctx.bezierCurveTo(106,106,107,103,107,101); + ctx.bezierCurveTo(107,99,106,96,103,96); + ctx.fill(); + ctx.fillStyle = "black"; + ctx.beginPath(); + ctx.arc(101,102,2,0,Math.PI*2,true); + ctx.fill(); + ctx.beginPath(); + ctx.arc(89,102,2,0,Math.PI*2,true); + ctx.fill(); +} +function roundedRect(ctx,x,y,width,height,radius){ + ctx.beginPath(); + ctx.moveTo(x,y+radius); + ctx.lineTo(x,y+height-radius); + ctx.quadraticCurveTo(x,y+height,x+radius,y+height); + ctx.lineTo(x+width-radius,y+height); + ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius); + ctx.lineTo(x+width,y+radius); + ctx.quadraticCurveTo(x+width,y,x+width-radius,y); + ctx.lineTo(x+radius,y); + ctx.quadraticCurveTo(x,y,x,y+radius); + ctx.stroke(); +} +*/ +debug("here10"); diff --git a/wsproxy.py b/wsproxy.py index 3d147801..b6c90e77 100755 --- a/wsproxy.py +++ b/wsproxy.py @@ -20,6 +20,10 @@ def handshake(client): _, host = req_lines[3].split(" ") client.send(server_handshake % (origin, host, path)) +def traffic(token="."): + sys.stdout.write(token) + sys.stdout.flush() + def proxy(client, target): cqueue = [] tqueue = [] @@ -33,23 +37,28 @@ def proxy(client, target): buf = client.recv(1024) if len(buf) == 0: raise Exception("Client closed") tqueue.append(buf[1:-1]) - print "Client recv: %s (%d)" % (buf[1:-1], len(buf)) + #print "Client recv: %s (%d)" % (buf[1:-1], len(buf)) + traffic("}") if target in ins: buf = target.recv(1024) if len(buf) == 0: raise Exception("Target closed") cqueue.append("\x00" + buf + "\xff") - print "Target recv: %s (%d)" % (buf, len(buf)) + #print "Target recv: %s (%d)" % (buf, len(buf)) + traffic("{") if cqueue and client in outs: while cqueue: - print "Client send: %s" % cqueue[0] + #print "Client send: %s" % cqueue[0] client.send(cqueue.pop(0)) + traffic("<") if tqueue and target in outs: while tqueue: - print "Target send: %s" % tqueue[0] + #print "Target send: %s" % tqueue[0] + sys.stdout.flush() target.send(tqueue.pop(0)) + traffic(">") def start_server(listen_port, target_host, target_port): lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)