/dev/middle.js

http://github.com/OpenRTMFP/ArcusNode · JavaScript · 295 lines · 208 code · 42 blank · 45 comment · 23 complexity · 83febfe1e425a630c556cba1a8499916 MD5 · raw file

  1. /**
  2. * Middle
  3. *
  4. * Copyright 2011 OpenRTMFP
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License received along this program for more
  15. * details (or else see http://www.gnu.org/licenses/).
  16. *
  17. * Author: arcusdev <arcus.node@gmail.com>
  18. *
  19. * This file is a part of ArcusNode.
  20. */
  21. var util = require('util');
  22. var dgram = require('dgram');
  23. var URL = require('url');
  24. var RTMFP = require('../lib/rtmfp.js');
  25. var NetConnection = require('../lib/net_connection');
  26. var Packet = require('../lib/packet.js');
  27. var FMS = {};
  28. var serverConnectionPort = Math.round(Math.random() * 45000) + 20000;
  29. var serverConnection = new NetConnection(5);
  30. var clientConnection = new NetConnection(10);
  31. //Take arguments
  32. process.argv.forEach(function (val, index, array) {
  33. if(index < 2)
  34. return;
  35. var valArr = val.split('=');
  36. switch(valArr[0]){
  37. case 'fms':
  38. FMS = URL.parse(valArr[1], false);
  39. console.log(FMS);
  40. if(!FMS.port){
  41. FMS.port = '1935';
  42. }
  43. FMS.address = FMS.hostname;
  44. break;
  45. default:
  46. util.print('\033[31mArgument unknown or malformed\033[0m: ' + val + '\nStopping process.');
  47. process.exit();
  48. }
  49. });
  50. //FMS = { address: '50.56.33.168', port: '10001', hostname: '50.56.33.168', pathname: '/9f562071a62ee15bc91c8eec-4b461ed21d0f'};
  51. var rtmfp = new RTMFP();
  52. var cpkt = null;
  53. // Setup connection to FMS
  54. var serverSocket = dgram.createSocket('udp4', function(buffer, remoteInfo){
  55. var pkt = new Packet(buffer, buffer.length);
  56. var id = rtmfp.decodePacket(pkt);
  57. if(id != 0 && serverConnection.state != NetConnection.HANDSHAKE){
  58. rtmfp.decryptPacket(pkt, serverConnection.__p.decryptKey);
  59. } else {
  60. rtmfp.decryptPacket(pkt, RTMFP.SYMETRIC_KEY);
  61. }
  62. try {
  63. var msgs = rtmfp.readPacket(pkt);
  64. } catch(e){
  65. console.log('RTMFP could not handle message from server.', e.stack);
  66. console.log('FMS to Client (unhandled): ', pkt.toString());
  67. rtmfp.encryptPacket(pkt, clientConnection.__p.encryptKey);
  68. rtmfp.encodePacket(pkt, clientConnection.__p.clientConnectionId);
  69. send(clientSocket, pkt, clientConnection.endpoints[0]);
  70. return;
  71. }
  72. for(k in msgs){
  73. var msg = msgs[k];
  74. switch(msg.type){
  75. // FORWARD
  76. case RTMFP.FORWARD_REQUEST:
  77. for(k in msg.endpoints){
  78. console.log('FORWARD ADDRESS: ', msg.endpoints[k]);
  79. }
  80. break;
  81. // HANDSHAKE_RESPONSE
  82. case RTMFP.HANDSHAKE_RESPONSE:
  83. msg.type = RTMFP.KEY_REQUEST;
  84. msg.connectionId = serverConnection.id;
  85. msg.publicKey = serverConnection.publicKey;
  86. msg.certificate = serverConnection.certificate;
  87. var pkt = new Packet(new Buffer(200), 0).clear();
  88. rtmfp.writePacket(pkt, msg);
  89. rtmfp.encryptPacket(pkt, RTMFP.SYMETRIC_KEY);
  90. rtmfp.encodePacket(pkt, 0);
  91. send(serverSocket, pkt, FMS);
  92. break;
  93. // KEY_RESPONSE
  94. case RTMFP.KEY_RESPONSE:
  95. serverConnection.computeSharedSecret(msg.publicKey);
  96. var serverNonce = new Packet(msg.signature.length + msg.publicKey.length);
  97. serverNonce.writeBuffer(msg.signature);
  98. serverNonce.writeBuffer(msg.publicKey);
  99. serverConnection.computeAsymetricKeys(serverNonce.buffer(), rtmfp.createClientNonce(serverConnection.certificate));
  100. serverConnection.__p.state = NetConnection.CONNECTED;
  101. serverConnection.__p.clientConnectionId = msg.connectionId;
  102. console.log('Server connection established, ready to loop through.');
  103. break;
  104. // Send to client
  105. default:
  106. console.log('FMS to Client: ', pkt.toString());
  107. rtmfp.encryptPacket(pkt, clientConnection.__p.encryptKey);
  108. rtmfp.encodePacket(pkt, clientConnection.__p.clientConnectionId);
  109. send(clientSocket, pkt, clientConnection.endpoints[0]);
  110. break;
  111. }
  112. }
  113. });
  114. serverSocket.bind(serverConnectionPort);
  115. var send = function(socket, packet, endpoint) {
  116. socket.send(packet.buffer(), 0, packet.size(), endpoint.port, endpoint.address, function (err, bytes) {
  117. if (err) {
  118. //TODO: Handle error and recover
  119. throw err;
  120. }
  121. });
  122. };
  123. //
  124. // Client Connections
  125. //
  126. var clientForwarder = dgram.createSocket('udp4', function(buffer, remoteInfo){
  127. var pkt = new Packet(buffer, buffer.length);
  128. var id = rtmfp.decodePacket(pkt);
  129. if(!rtmfp.decryptPacket(pkt, RTMFP.SYMETRIC_KEY)){
  130. console.log('Client initial message decryption failed');
  131. return;
  132. }
  133. console.log('Received Client Handshake:', pkt.toString());
  134. var msgs = rtmfp.readPacket(pkt);
  135. for(k in msgs){
  136. var message = msgs[k];
  137. switch(message.type){
  138. // HANDSHAKE_REQUEST
  139. case RTMFP.HANDSHAKE_REQUEST:
  140. var msg = {
  141. type: RTMFP.FORWARD_REQUEST,
  142. endpoints: [ { address: '192.168.244.134', port: 20001 } ],
  143. tag: message.tag
  144. };
  145. var responsePacket = new Packet(128);
  146. rtmfp.writePacket(responsePacket, msg);
  147. console.log('Forwarding Client', responsePacket.toString());
  148. rtmfp.encryptPacket(responsePacket, RTMFP.SYMETRIC_KEY);
  149. rtmfp.encodePacket(responsePacket, 0);
  150. send(clientForwarder, responsePacket, remoteInfo);
  151. break;
  152. }
  153. }
  154. });
  155. clientForwarder.bind(1935);
  156. var clientSocket = dgram.createSocket('udp4', function(buffer, remoteInfo){
  157. var pkt = new Packet(buffer, buffer.length);
  158. var id = rtmfp.decodePacket(pkt);
  159. var decrypted = false;
  160. if(id != 0 && clientConnection.state != NetConnection.HANDSHAKE){
  161. decrypted = rtmfp.decryptPacket(pkt, clientConnection.__p.decryptKey);
  162. } else {
  163. decrypted = rtmfp.decryptPacket(pkt, RTMFP.SYMETRIC_KEY);
  164. }
  165. if(!decrypted){
  166. console.log('Client message decryption failed');
  167. return;
  168. }
  169. try {
  170. var msgs = rtmfp.readPacket(pkt);
  171. } catch(e){
  172. console.log('RTMFP could not handle message from client.', e.stack);
  173. console.log('Client to FMS (unhandled): ', pkt.toString());
  174. rtmfp.encryptPacket(pkt, serverConnection.__p.encryptKey);
  175. rtmfp.encodePacket(pkt, serverConnection.__p.clientConnectionId);
  176. send(clientSocket, pkt, FMS);
  177. return;
  178. }
  179. for(k in msgs){
  180. var message = msgs[k];
  181. switch(message.type){
  182. // HANDSHAKE_REQUEST
  183. case RTMFP.HANDSHAKE_REQUEST:
  184. console.log('Received handler client handshake:', pkt.toString());
  185. //Generate Cookie
  186. message.cookie = Packet.randomBytes(64);
  187. message.certificate = clientConnection.certificate;
  188. //Create Response
  189. if(clientConnection.state == NetConnection.HANDSHAKE){
  190. message.type = RTMFP.HANDSHAKE_RESPONSE;
  191. var responsePacket = new Packet(255);
  192. rtmfp.writePacket(responsePacket, message);
  193. rtmfp.encryptPacket(responsePacket, RTMFP.SYMETRIC_KEY);
  194. rtmfp.encodePacket(responsePacket, 0);
  195. send(clientSocket, responsePacket, remoteInfo);
  196. }
  197. break;
  198. // KEY_REQUEST
  199. case RTMFP.KEY_REQUEST:
  200. if(clientConnection.state != NetConnection.HANDSHAKE)
  201. return;
  202. clientConnection.__p.state = NetConnection.CONNECTED;
  203. //the clientConnectionId is used to encode it to a response packet
  204. clientConnection.__p.clientConnectionId = message.connectionId;
  205. console.log('Client Connection Id', message.connectionId);
  206. //This will be used by the client to encode it to a packet so the server can lookup connections
  207. message.connectionId = clientConnection.id;
  208. clientConnection.endpoints.push(remoteInfo);
  209. //Do key exchange
  210. clientConnection.computeSharedSecret(message.publicKey);
  211. message.publicKey = clientConnection.publicKey;
  212. var serverNonce = rtmfp.createServerNonce(clientConnection.publicKey);
  213. clientConnection.computeAsymetricKeys(message.clientCertificate, serverNonce);
  214. message.type = RTMFP.KEY_RESPONSE
  215. var responsePacket = new Packet(255);
  216. rtmfp.writePacket(responsePacket, message);
  217. rtmfp.encryptPacket(responsePacket, RTMFP.SYMETRIC_KEY);
  218. rtmfp.encodePacket(responsePacket, clientConnection.__p.clientConnectionId);
  219. send(clientSocket, responsePacket, clientConnection.endpoints[0]);
  220. console.log('Client connection established, ready to loop through.');
  221. break;
  222. // NET_CONNECTION_REQUEST
  223. case RTMFP.NET_CONNECTION_REQUEST:
  224. console.log('Client to FMS (connect original): ', pkt.toString());
  225. message.url = 'rtmfp://' + FMS.hostname + ((FMS.pathname) ? FMS.pathname : '');
  226. message.app = ((FMS.pathname) ? FMS.pathname : '').substr(1);
  227. pkt = new Packet(300);
  228. rtmfp.writePacket(pkt, message);
  229. // >>
  230. // Send to server
  231. default:
  232. console.log('Client to FMS: ', pkt.toString());
  233. rtmfp.encryptPacket(pkt, serverConnection.__p.encryptKey);
  234. rtmfp.encodePacket(pkt, serverConnection.__p.clientConnectionId);
  235. send(serverSocket, pkt, FMS);
  236. break;
  237. }
  238. }
  239. });
  240. clientSocket.bind(20001);
  241. //
  242. // Init connection to FMS
  243. //
  244. var message = {};
  245. message.type = RTMFP.HANDSHAKE_REQUEST;
  246. message.url = 'rtmfp://' + FMS.hostname + ((FMS.pathname) ? FMS.pathname : '');
  247. message.tag = Packet.randomBytes(16, new Buffer(16), 0);
  248. var pkt = new Packet(64);
  249. rtmfp.writePacket(pkt, message);
  250. console.log(pkt.toString());
  251. rtmfp.encryptPacket(pkt, RTMFP.SYMETRIC_KEY);
  252. rtmfp.encodePacket(pkt, 0);
  253. send(serverSocket, pkt, FMS);