Compare commits
	
		
			No commits in common. "master" and "v1.5.0" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										109
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										109
									
								
								README.md
									
									
									
									
									
								
							| @ -1,4 +1,6 @@ | |||||||
| # proxy-packer | a [Root](https://rootprojects.org) project | # proxy-packer | ||||||
|  | 
 | ||||||
|  | | Sponsored by [ppl](https://ppl.family) | | ||||||
| 
 | 
 | ||||||
| "The M-PROXY Protocol" for node.js | "The M-PROXY Protocol" for node.js | ||||||
| 
 | 
 | ||||||
| @ -15,7 +17,8 @@ Browser <--/                   \--> Device | |||||||
| 
 | 
 | ||||||
| It's the kind of thing you'd use to build a poor man's VPN, or port-forward router. | It's the kind of thing you'd use to build a poor man's VPN, or port-forward router. | ||||||
| 
 | 
 | ||||||
| # The M-PROXY Protocol | The M-PROXY Protocol | ||||||
|  | =================== | ||||||
| 
 | 
 | ||||||
| This is similar to "The PROXY Protocol" (a la HAProxy), but desgined for multiplexed tls, http, tcp, and udp | This is similar to "The PROXY Protocol" (a la HAProxy), but desgined for multiplexed tls, http, tcp, and udp | ||||||
| tunneled over arbitrary streams (such as WebSockets). | tunneled over arbitrary streams (such as WebSockets). | ||||||
| @ -57,7 +60,8 @@ service port             (string) The listening port, such as 443. Useful for no | |||||||
| host or server name      (string) Useful for services that can be routed by name, such as http, https, smtp, and dns. | host or server name      (string) Useful for services that can be routed by name, such as http, https, smtp, and dns. | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Tunneled TCP SNI Packet | Tunneled TCP SNI Packet | ||||||
|  | ----------------------- | ||||||
| 
 | 
 | ||||||
| You should see that the result is simply all of the original packet with a leading header. | You should see that the result is simply all of the original packet with a leading header. | ||||||
| 
 | 
 | ||||||
| @ -87,13 +91,15 @@ Note that `16 03 01 00` starts at the 29th byte (at index 28 or 0x1C) instead of | |||||||
| The v1 header uses strings for address and service descriptor information, | The v1 header uses strings for address and service descriptor information, | ||||||
| but future versions may be binary. | but future versions may be binary. | ||||||
| 
 | 
 | ||||||
| # API | API | ||||||
|  | === | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| var Packer = require('proxy-packer'); | var Packer = require('proxy-packer'); | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Unpacker / Parser State Machine | Unpacker / Parser State Machine | ||||||
|  | ----------------------- | ||||||
| 
 | 
 | ||||||
| The unpacker creates a state machine. | The unpacker creates a state machine. | ||||||
| 
 | 
 | ||||||
| @ -102,52 +108,52 @@ composing a full message with header and data (unless data length is 0). | |||||||
| 
 | 
 | ||||||
| The state machine progresses through these states: | The state machine progresses through these states: | ||||||
| 
 | 
 | ||||||
| -   version | * version | ||||||
| -   headerLength | * headerLength | ||||||
| -   header | * header | ||||||
| -   data | * data | ||||||
| 
 | 
 | ||||||
| At the end of the data event (which may or may not contain a buffer of data) | At the end of the data event (which may or may not contain a buffer of data) | ||||||
| one of the appropriate handlers will be called. | one of the appropriate handlers will be called. | ||||||
| 
 | 
 | ||||||
| -   control | * control | ||||||
| -   connection | * connection | ||||||
| -   message | * message | ||||||
| -   pause | * pause | ||||||
| -   resume | * resume | ||||||
| -   end | * end | ||||||
| -   error | * error | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| unpacker = Packer.create(handlers);                       // Create a state machine for unpacking | unpacker = Packer.create(handlers);                       // Create a state machine for unpacking | ||||||
| 
 | 
 | ||||||
| unpacker.fns.addData(chunk);                              // process a chunk of data | unpacker.fns.addData(chunk);                              // process a chunk of data | ||||||
| 
 | 
 | ||||||
| handlers.oncontrol = function(tun) {}; // for communicating with the proxy | handlers.oncontrol = function (tun) { }                   // for communicating with the proxy | ||||||
| // tun.data is an array |                                                           // tun.data is an array | ||||||
| //     '[ -1, "[Error] bad hello" ]' |                                                           //     '[ -1, "[Error] bad hello" ]' | ||||||
| //     '[ 0, "[Error] out-of-band error message" ]' |                                                           //     '[ 0, "[Error] out-of-band error message" ]' | ||||||
| //     '[ 1, "hello", 254, [ "add_token", "delete_token" ] ]' |                                                           //     '[ 1, "hello", 254, [ "add_token", "delete_token" ] ]' | ||||||
| //     '[ 1, "add_token" ]' |                                                           //     '[ 1, "add_token" ]' | ||||||
| //     '[ 1, "delete_token" ]' |                                                           //     '[ 1, "delete_token" ]' | ||||||
| 
 | 
 | ||||||
| handlers.onconnection = function(tun) {}; // a client has established a connection | handlers.onconnection = function (tun) { }                // a client has established a connection | ||||||
| 
 | 
 | ||||||
| handlers.onmessage = function(tun) {}; // a client has sent a message | handlers.onmessage = function (tun) { }                   // a client has sent a message | ||||||
| // tun = { family, address, port, data |                                                           // tun = { family, address, port, data | ||||||
| //       , service, serviceport, name }; |                                                           //       , service, serviceport, name }; | ||||||
| 
 | 
 | ||||||
| handlers.onpause = function(tun) {}; // proxy requests to pause upload to a client | handlers.onpause = function (tun) { }                     // proxy requests to pause upload to a client | ||||||
| // tun = { family, address, port }; |                                                           // tun = { family, address, port }; | ||||||
| 
 | 
 | ||||||
| handlers.onresume = function(tun) {}; // proxy requests to resume upload to a client | handlers.onresume = function (tun) { }                    // proxy requests to resume upload to a client | ||||||
| // tun = { family, address, port }; |                                                           // tun = { family, address, port }; | ||||||
| 
 | 
 | ||||||
| handlers.onend = function(tun) {}; // proxy requests to close a client's socket | handlers.onend = function (tun) { }                       // proxy requests to close a client's socket | ||||||
| // tun = { family, address, port }; |                                                           // tun = { family, address, port }; | ||||||
| 
 | 
 | ||||||
| handlers.onerror = function(err) {}; // proxy is relaying a client's error | handlers.onerror = function (err) { }                     // proxy is relaying a client's error | ||||||
| // err = { message, family, address, port }; |                                                           // err = { message, family, address, port }; | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| <!-- | <!-- | ||||||
| @ -157,17 +163,18 @@ handlers.onconnect = function (tun) { }                   // a new client has co | |||||||
| 
 | 
 | ||||||
| --> | --> | ||||||
| 
 | 
 | ||||||
| ## Packer & Extras | Packer & Extras | ||||||
|  | ------ | ||||||
| 
 | 
 | ||||||
| Packs header metadata about connection into a buffer (potentially with original data), ready to send. | Packs header metadata about connection into a buffer (potentially with original data), ready to send. | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| var headerAndBody = Packer.pack(tun, data);               // Add M-PROXY header to data | var headerAndBody = Packer.pack(tun, data);               // Add M-PROXY header to data | ||||||
| // tun = { family, address, port |                                                           // tun = { family, address, port | ||||||
| //       , service, serviceport, name } |                                                           //       , service, serviceport, name } | ||||||
| 
 | 
 | ||||||
| var headerBuf = Packer.packHeader(tun, data);             // Same as above, but creates a buffer for header only | var headerBuf = Packer.packHeader(tun, data);             // Same as above, but creates a buffer for header only | ||||||
| // (data can be converted to a buffer or sent as-is) |                                                           // (data can be converted to a buffer or sent as-is) | ||||||
| 
 | 
 | ||||||
| var addr = Packer.socketToAddr(socket);                   // Probe raw, raw socket for address info | var addr = Packer.socketToAddr(socket);                   // Probe raw, raw socket for address info | ||||||
| 
 | 
 | ||||||
| @ -180,20 +187,20 @@ var id = Packer.socketToId(socket); // Turn raw, raw socket info into a determin | |||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| var socket = Packer.Stream.wrapSocket(socketOrStream);   // workaround for https://github.com/nodejs/node/issues/8854 | var socket = Packer.Stream.wrapSocket(socketOrStream);   // workaround for https://github.com/nodejs/node/issues/8854 | ||||||
| // which was just closed recently, but probably still needs |                                                          // which was just closed recently, but probably still needs | ||||||
| // something more like this (below) to work as intended |                                                          // something more like this (below) to work as intended | ||||||
| // https://github.com/findhit/proxywrap/blob/master/lib/proxywrap.js |                                                          // https://github.com/findhit/proxywrap/blob/master/lib/proxywrap.js | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| var myTransform = Packer.Transform.create({ | var myTransform = Packer.Transform.create({ | ||||||
|   address: { |   address: { | ||||||
| 		family: '...', |     family: '...' | ||||||
| 		address: '...', |   , address: '...' | ||||||
| 		port: '...' |   , port: '...' | ||||||
| 	}, |   } | ||||||
|   // hint at the service to be used |   // hint at the service to be used | ||||||
| 	service: 'https' | , service: 'https' | ||||||
| }); | }); | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| @ -210,7 +217,6 @@ hexdump output.bin | |||||||
| Where `input.json` looks something like this: | Where `input.json` looks something like this: | ||||||
| 
 | 
 | ||||||
| `input.json`: | `input.json`: | ||||||
| 
 |  | ||||||
| ``` | ``` | ||||||
| { "version": 1 | { "version": 1 | ||||||
| , "address": { | , "address": { | ||||||
| @ -225,12 +231,12 @@ Where `input.json` looks something like this: | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Raw TCP SNI Packet | Raw TCP SNI Packet | ||||||
|  | ------------------ | ||||||
| 
 | 
 | ||||||
| and `sni.tcp.bin` is any captured tcp packet, such as this one with a tls hello: | and `sni.tcp.bin` is any captured tcp packet, such as this one with a tls hello: | ||||||
| 
 | 
 | ||||||
| `sni.tcp.bin`: | `sni.tcp.bin`: | ||||||
| 
 |  | ||||||
| ``` | ``` | ||||||
|          0  1  2  3  4  5  6  7  8  9  A  B  C  D  D  F |          0  1  2  3  4  5  6  7  8  9  A  B  C  D  D  F | ||||||
| 0000000 16 03 01 00 c2 01 00 00 be 03 03 57 e3 76 50 66 | 0000000 16 03 01 00 c2 01 00 00 be 03 03 57 e3 76 50 66 | ||||||
| @ -249,7 +255,8 @@ and `sni.tcp.bin` is any captured tcp packet, such as this one with a tls hello: | |||||||
| 00000c7 | 00000c7 | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## Tunneled TCP SNI Packet | Tunneled TCP SNI Packet | ||||||
|  | ----------------------- | ||||||
| 
 | 
 | ||||||
| You should see that the result is simply all of the original packet with a leading header. | You should see that the result is simply all of the original packet with a leading header. | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										235
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										235
									
								
								index.js
									
									
									
									
									
								
							| @ -3,37 +3,36 @@ | |||||||
| var Packer = module.exports; | var Packer = module.exports; | ||||||
| 
 | 
 | ||||||
| var serviceEvents = { | var serviceEvents = { | ||||||
| 	default: 'tunnelData', |   default: 'tunnelData' | ||||||
| 	connection: 'tunnelConnection', | , connection: 'tunnelConnection' | ||||||
| 	control: 'tunnelControl', | , control: 'tunnelControl' | ||||||
| 	error: 'tunnelError', | , error:   'tunnelError' | ||||||
| 	end: 'tunnelEnd', | , end:     'tunnelEnd' | ||||||
| 	pause: 'tunnelPause', | , pause:   'tunnelPause' | ||||||
| 	resume: 'tunnelResume' | , resume:  'tunnelResume' | ||||||
| }; | }; | ||||||
| var serviceFuncs = { | var serviceFuncs = { | ||||||
| 	default: 'onmessage', |   default: 'onmessage' | ||||||
| 	connection: 'onconnection', | , connection: 'onconnection' | ||||||
| 	control: 'oncontrol', | , control: 'oncontrol' | ||||||
| 	error: 'onerror', | , error:   'onerror' | ||||||
| 	end: 'onend', | , end:     'onend' | ||||||
| 	pause: 'onpause', | , pause:   'onpause' | ||||||
| 	resume: 'onresume' | , resume:  'onresume' | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Packer.create = function(opts) { | Packer.create = function (opts) { | ||||||
|   var machine; |   var machine; | ||||||
| 
 | 
 | ||||||
|   if (!opts.onMessage && !opts.onmessage) { |   if (!opts.onMessage && !opts.onmessage) { | ||||||
| 		machine = new (require('events')).EventEmitter(); |     machine = new (require('events').EventEmitter)(); | ||||||
|   } else { |   } else { | ||||||
|     machine = {}; |     machine = {}; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   machine.onmessage    = opts.onmessage    || opts.onMessage; |   machine.onmessage    = opts.onmessage    || opts.onMessage; | ||||||
|   machine.oncontrol    = opts.oncontrol    || opts.onControl; |   machine.oncontrol    = opts.oncontrol    || opts.onControl; | ||||||
| 	machine.onconnection = |   machine.onconnection = opts.onconnection || opts.onConnection || function () {}; | ||||||
| 		opts.onconnection || opts.onConnection || function() {}; |  | ||||||
|   machine.onerror      = opts.onerror      || opts.onError; |   machine.onerror      = opts.onerror      || opts.onError; | ||||||
|   machine.onend        = opts.onend        || opts.onEnd; |   machine.onend        = opts.onend        || opts.onEnd; | ||||||
|   machine.onpause      = opts.onpause      || opts.onPause; |   machine.onpause      = opts.onpause      || opts.onPause; | ||||||
| @ -45,9 +44,9 @@ Packer.create = function(opts) { | |||||||
|   machine.chunkIndex = 0; |   machine.chunkIndex = 0; | ||||||
|   machine.buf = null; |   machine.buf = null; | ||||||
|   machine.bufIndex = 0; |   machine.bufIndex = 0; | ||||||
| 	machine.fns.collectData = function(chunk, size) { |   machine.fns.collectData = function (chunk, size) { | ||||||
|     var chunkLeft = chunk.length - machine.chunkIndex; |     var chunkLeft = chunk.length - machine.chunkIndex; | ||||||
| 		var hasLen = size > 0; |     var hasLen = (size > 0); | ||||||
| 
 | 
 | ||||||
|     if (!hasLen) { |     if (!hasLen) { | ||||||
|       return Buffer.alloc(0); |       return Buffer.alloc(0); | ||||||
| @ -68,10 +67,7 @@ Packer.create = function(opts) { | |||||||
| 
 | 
 | ||||||
|     // Read and mark as read however much data we need from the chunk to complete our buffer.
 |     // Read and mark as read however much data we need from the chunk to complete our buffer.
 | ||||||
|     var partLen = size - machine.bufIndex; |     var partLen = size - machine.bufIndex; | ||||||
| 		var part = chunk.slice( |     var part = chunk.slice(machine.chunkIndex, machine.chunkIndex+partLen); | ||||||
| 			machine.chunkIndex, |  | ||||||
| 			machine.chunkIndex + partLen |  | ||||||
| 		); |  | ||||||
|     machine.chunkIndex += partLen; |     machine.chunkIndex += partLen; | ||||||
| 
 | 
 | ||||||
|     // If we had nothing buffered than the part of the chunk we just read is all we need.
 |     // If we had nothing buffered than the part of the chunk we just read is all we need.
 | ||||||
| @ -88,11 +84,11 @@ Packer.create = function(opts) { | |||||||
|     return buf; |     return buf; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| 	machine.fns.version = function(chunk) { |   machine.fns.version = function (chunk) { | ||||||
|     //console.log('');
 |     //console.log('');
 | ||||||
|     //console.log('[version]');
 |     //console.log('[version]');
 | ||||||
| 		if (255 - machine._version !== chunk[machine.chunkIndex]) { |     if ((255 - machine._version) !== chunk[machine.chunkIndex]) { | ||||||
| 			console.error('not v' + machine._version + ' (or data is corrupt)'); |       console.error("not v" + machine._version + " (or data is corrupt)"); | ||||||
|       // no idea how to fix this yet
 |       // no idea how to fix this yet
 | ||||||
|     } |     } | ||||||
|     machine.chunkIndex += 1; |     machine.chunkIndex += 1; | ||||||
| @ -100,8 +96,9 @@ Packer.create = function(opts) { | |||||||
|     return true; |     return true; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|   machine.headerLen = 0; |   machine.headerLen = 0; | ||||||
| 	machine.fns.headerLength = function(chunk) { |   machine.fns.headerLength = function (chunk) { | ||||||
|     //console.log('');
 |     //console.log('');
 | ||||||
|     //console.log('[headerLength]');
 |     //console.log('[headerLength]');
 | ||||||
|     machine.headerLen = chunk[machine.chunkIndex]; |     machine.headerLen = chunk[machine.chunkIndex]; | ||||||
| @ -110,7 +107,7 @@ Packer.create = function(opts) { | |||||||
|     return true; |     return true; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| 	machine.fns.header = function(chunk) { |   machine.fns.header = function (chunk) { | ||||||
|     //console.log('');
 |     //console.log('');
 | ||||||
|     //console.log('[header]');
 |     //console.log('[header]');
 | ||||||
|     var header = machine.fns.collectData(chunk, machine.headerLen); |     var header = machine.fns.collectData(chunk, machine.headerLen); | ||||||
| @ -129,13 +126,12 @@ Packer.create = function(opts) { | |||||||
|     machine.service     = machine._headers[4]; |     machine.service     = machine._headers[4]; | ||||||
|     machine.serviceport = machine._headers[5]; |     machine.serviceport = machine._headers[5]; | ||||||
|     machine.name        = machine._headers[6]; |     machine.name        = machine._headers[6]; | ||||||
| 		machine.servicename = machine._headers[7]; |  | ||||||
|     //console.log('machine.service', machine.service);
 |     //console.log('machine.service', machine.service);
 | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| 	machine.fns.data = function(chunk) { |   machine.fns.data = function (chunk) { | ||||||
|     //console.log('');
 |     //console.log('');
 | ||||||
|     //console.log('[data]');
 |     //console.log('[data]');
 | ||||||
|     var data; |     var data; | ||||||
| @ -149,6 +145,7 @@ Packer.create = function(opts) { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     //
 |     //
 | ||||||
|     // data, end, error
 |     // data, end, error
 | ||||||
|     //
 |     //
 | ||||||
| @ -156,8 +153,8 @@ Packer.create = function(opts) { | |||||||
|     if ('error' === machine.service) { |     if ('error' === machine.service) { | ||||||
|       try { |       try { | ||||||
|         msg = JSON.parse(data.toString()); |         msg = JSON.parse(data.toString()); | ||||||
| 			} catch (e) { |       } catch(e) { | ||||||
| 				msg.message = 'e:' + JSON.stringify(data); |         msg.message = data.toString(); | ||||||
|         msg.code = 'E_UNKNOWN_ERR'; |         msg.code = 'E_UNKNOWN_ERR'; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -170,21 +167,10 @@ Packer.create = function(opts) { | |||||||
|     msg.name        = machine.name; |     msg.name        = machine.name; | ||||||
|     msg.data        = data; |     msg.data        = data; | ||||||
| 
 | 
 | ||||||
| 		if ('connection' === machine.service) { |  | ||||||
| 			msg.service = machine.servicename; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		//console.log('msn', machine.service);
 |  | ||||||
|     if (machine.emit) { |     if (machine.emit) { | ||||||
| 			machine.emit( |       machine.emit(serviceEvents[msg.service] || serviceEvents.default); | ||||||
| 				serviceEvents[machine.service] || |  | ||||||
| 					serviceEvents[msg.service] || |  | ||||||
| 					serviceEvents.default |  | ||||||
| 			); |  | ||||||
|     } else { |     } else { | ||||||
| 			(machine[serviceFuncs[machine.service]] || |       (machine[serviceFuncs[msg.service]] || machine[serviceFuncs.default])(msg); | ||||||
| 				machine[serviceFuncs[msg.service]] || |  | ||||||
| 				machine[serviceFuncs.default])(msg); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return true; |     return true; | ||||||
| @ -192,7 +178,7 @@ Packer.create = function(opts) { | |||||||
| 
 | 
 | ||||||
|   machine.state = 0; |   machine.state = 0; | ||||||
|   machine.states = ['version', 'headerLength', 'header', 'data']; |   machine.states = ['version', 'headerLength', 'header', 'data']; | ||||||
| 	machine.fns.addChunk = function(chunk) { |   machine.fns.addChunk = function (chunk) { | ||||||
|     //console.log('');
 |     //console.log('');
 | ||||||
|     //console.log('[addChunk]');
 |     //console.log('[addChunk]');
 | ||||||
|     machine.chunkIndex = 0; |     machine.chunkIndex = 0; | ||||||
| @ -204,78 +190,49 @@ Packer.create = function(opts) { | |||||||
|         machine.state %= machine.states.length; |         machine.state %= machine.states.length; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 		if ('data' === machine.states[machine.state] && 0 === machine.bodyLen) { |  | ||||||
| 			machine.fns[machine.states[machine.state]](chunk); |  | ||||||
| 			machine.state += 1; |  | ||||||
| 			machine.state %= machine.states.length; |  | ||||||
| 		} |  | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   return machine; |   return machine; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Packer.packHeader = function(meta, data, service, andBody, oldways) { | Packer.packHeader = function (meta, data, service, andBody, oldways) { | ||||||
| 	if (oldways && !data) { |   if (oldways) { | ||||||
| 		data = Buffer.from(' '); |     data = data || Buffer.from(' '); | ||||||
|   } |   } | ||||||
|   if (data && !Buffer.isBuffer(data)) { |   if (data && !Buffer.isBuffer(data)) { | ||||||
| 		data = Buffer.from(JSON.stringify(data)); |     data = new Buffer(JSON.stringify(data)); | ||||||
|   } |   } | ||||||
|   if (oldways && !data.byteLength) { |   if (oldways && !data.byteLength) { | ||||||
|     data = Buffer.from(' '); |     data = Buffer.from(' '); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 	if (service && -1 === ['control', 'connection'].indexOf(service)) { |   if (service && service !== 'control') { | ||||||
| 		//console.log('end?', service);
 |  | ||||||
|     meta.service = service; |     meta.service = service; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 	var size = (data && data.byteLength) || 0; |   var size = data && data.byteLength || 0; | ||||||
|   var sizeReserve = andBody ? size : 0; |   var sizeReserve = andBody ? size : 0; | ||||||
|   var version = 1; |   var version = 1; | ||||||
|   var header; |   var header; | ||||||
|   if (service === 'control') { |   if (service === 'control') { | ||||||
|     header = Buffer.from(['', '', '', size, service].join(',')); |     header = Buffer.from(['', '', '', size, service].join(',')); | ||||||
| 	} else if (service === 'connection') { |  | ||||||
| 		header = Buffer.from( |  | ||||||
| 			[ |  | ||||||
| 				meta.family, |  | ||||||
| 				meta.address, |  | ||||||
| 				meta.port, |  | ||||||
| 				size, |  | ||||||
| 				'connection', |  | ||||||
| 				meta.serviceport || '', |  | ||||||
| 				meta.name || '', |  | ||||||
| 				meta.service || '' |  | ||||||
| 			].join(',') |  | ||||||
| 		); |  | ||||||
| 	} else { |  | ||||||
| 		header = Buffer.from( |  | ||||||
| 			[ |  | ||||||
| 				meta.family, |  | ||||||
| 				meta.address, |  | ||||||
| 				meta.port, |  | ||||||
| 				size, |  | ||||||
| 				meta.service || '', |  | ||||||
| 				meta.serviceport || '', |  | ||||||
| 				meta.name || '' |  | ||||||
| 			].join(',') |  | ||||||
| 		); |  | ||||||
|   } |   } | ||||||
| 	var metaBuf = Buffer.from([255 - version, header.length]); |   else { | ||||||
| 	var buf = Buffer.alloc( |     header = Buffer.from([ | ||||||
| 		metaBuf.byteLength + header.byteLength + sizeReserve |       meta.family, meta.address, meta.port, size, | ||||||
| 	); |       (meta.service || ''), (meta.serviceport || ''), (meta.name || '') | ||||||
|  |     ].join(',')); | ||||||
|  |   } | ||||||
|  |   var metaBuf = Buffer.from([ 255 - version, header.length ]); | ||||||
|  |   var buf = Buffer.alloc(metaBuf.byteLength + header.byteLength + sizeReserve); | ||||||
| 
 | 
 | ||||||
|   metaBuf.copy(buf, 0); |   metaBuf.copy(buf, 0); | ||||||
|   header.copy(buf, 2); |   header.copy(buf, 2); | ||||||
| 	if (sizeReserve) { |   if (sizeReserve) { data.copy(buf, 2 + header.byteLength); } | ||||||
| 		data.copy(buf, 2 + header.byteLength); |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
|   return buf; |   return buf; | ||||||
| }; | }; | ||||||
| Packer.pack = function(meta, data, service) { | Packer.pack = function (meta, data, service) { | ||||||
|   return Packer.packHeader(meta, data, service, true, true); |   return Packer.packHeader(meta, data, service, true, true); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -283,43 +240,42 @@ function extractSocketProps(socket, propNames) { | |||||||
|   var props = {}; |   var props = {}; | ||||||
| 
 | 
 | ||||||
|   if (socket.remotePort) { |   if (socket.remotePort) { | ||||||
| 		propNames.forEach(function(propName) { |     propNames.forEach(function (propName) { | ||||||
|       props[propName] = socket[propName]; |       props[propName] = socket[propName]; | ||||||
|     }); |     }); | ||||||
|   } else if (socket._remotePort) { |   } else if (socket._remotePort) { | ||||||
| 		propNames.forEach(function(propName) { |     propNames.forEach(function (propName) { | ||||||
|       props[propName] = socket['_' + propName]; |       props[propName] = socket['_' + propName]; | ||||||
|     }); |     }); | ||||||
| 	} else if (socket._handle) { |   } else if ( | ||||||
| 		if ( |     socket._handle | ||||||
| 			socket._handle._parent && |     && socket._handle._parent | ||||||
| 			socket._handle._parent.owner && |     && socket._handle._parent.owner | ||||||
| 			socket._handle._parent.owner.stream && |     && socket._handle._parent.owner.stream | ||||||
| 			socket._handle._parent.owner.stream.remotePort |     && socket._handle._parent.owner.stream.remotePort | ||||||
|   ) { |   ) { | ||||||
| 			propNames.forEach(function(propName) { |     propNames.forEach(function (propName) { | ||||||
|       props[propName] = socket._handle._parent.owner.stream[propName]; |       props[propName] = socket._handle._parent.owner.stream[propName]; | ||||||
|     }); |     }); | ||||||
|   } else if ( |   } else if ( | ||||||
| 			socket._handle._parentWrap && |     socket._handle._parentWrap | ||||||
| 			socket._handle._parentWrap.remotePort |     && socket._handle._parentWrap | ||||||
|  |     && socket._handle._parentWrap.remotePort | ||||||
|   ) { |   ) { | ||||||
| 			propNames.forEach(function(propName) { |     propNames.forEach(function (propName) { | ||||||
|       props[propName] = socket._handle._parentWrap[propName]; |       props[propName] = socket._handle._parentWrap[propName]; | ||||||
|     }); |     }); | ||||||
|   } else if ( |   } else if ( | ||||||
| 			socket._handle._parentWrap && |     socket._handle._parentWrap | ||||||
| 			socket._handle._parentWrap._handle && |     && socket._handle._parentWrap._handle | ||||||
| 			socket._handle._parentWrap._handle.owner && |     && socket._handle._parentWrap._handle.owner | ||||||
| 			socket._handle._parentWrap._handle.owner.stream && |     && socket._handle._parentWrap._handle.owner.stream | ||||||
| 			socket._handle._parentWrap._handle.owner.stream.remotePort |     && socket._handle._parentWrap._handle.owner.stream.remotePort | ||||||
|   ) { |   ) { | ||||||
| 			propNames.forEach(function(propName) { |     propNames.forEach(function (propName) { | ||||||
| 				props[propName] = |       props[propName] = socket._handle._parentWrap._handle.owner.stream[propName]; | ||||||
| 					socket._handle._parentWrap._handle.owner.stream[propName]; |  | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 	} |  | ||||||
|   return props; |   return props; | ||||||
| } | } | ||||||
| function extractSocketProp(socket, propName) { | function extractSocketProp(socket, propName) { | ||||||
| @ -331,48 +287,42 @@ function extractSocketProp(socket, propName) { | |||||||
| 
 | 
 | ||||||
|   try { |   try { | ||||||
|     value = value || socket._handle._parentWrap[propName]; |     value = value || socket._handle._parentWrap[propName]; | ||||||
| 		value = |     value = value || socket._handle._parentWrap._handle.owner.stream[propName]; | ||||||
| 			value || socket._handle._parentWrap._handle.owner.stream[propName]; |  | ||||||
|   } catch (e) {} |   } catch (e) {} | ||||||
| 
 | 
 | ||||||
|   return value || ''; |   return value || ''; | ||||||
| } | } | ||||||
| Packer.socketToAddr = function(socket) { | Packer.socketToAddr = function (socket) { | ||||||
|   // TODO BUG XXX
 |   // TODO BUG XXX
 | ||||||
|   // https://github.com/nodejs/node/issues/8854
 |   // https://github.com/nodejs/node/issues/8854
 | ||||||
|   // tlsSocket.remoteAddress = remoteAddress; // causes core dump
 |   // tlsSocket.remoteAddress = remoteAddress; // causes core dump
 | ||||||
|   // console.log(tlsSocket.remoteAddress);
 |   // console.log(tlsSocket.remoteAddress);
 | ||||||
| 
 | 
 | ||||||
| 	var props = extractSocketProps(socket, [ |   var props = extractSocketProps(socket, [ 'remoteFamily', 'remoteAddress', 'remotePort', 'localPort' ]); | ||||||
| 		'remoteFamily', |  | ||||||
| 		'remoteAddress', |  | ||||||
| 		'remotePort', |  | ||||||
| 		'localPort' |  | ||||||
| 	]); |  | ||||||
|   return { |   return { | ||||||
| 		family: props.remoteFamily, |     family:  props.remoteFamily | ||||||
| 		address: props.remoteAddress, |   , address: props.remoteAddress | ||||||
| 		port: props.remotePort, |   , port:    props.remotePort | ||||||
| 		serviceport: props.localPort |   , serviceport: props.localPort | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Packer.addrToId = function(address) { | Packer.addrToId = function (address) { | ||||||
|   return address.family + ',' + address.address + ',' + address.port; |   return address.family + ',' + address.address + ',' + address.port; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Packer.socketToId = function(socket) { | Packer.socketToId = function (socket) { | ||||||
|   return Packer.addrToId(Packer.socketToAddr(socket)); |   return Packer.addrToId(Packer.socketToAddr(socket)); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| var addressNames = [ | var addressNames = [ | ||||||
| 	'remoteAddress', |   'remoteAddress' | ||||||
| 	'remotePort', | , 'remotePort' | ||||||
| 	'remoteFamily', | , 'remoteFamily' | ||||||
| 	'localAddress', | , 'localAddress' | ||||||
| 	'localPort' | , 'localPort' | ||||||
| ]; | ]; | ||||||
| /* |  | ||||||
| var sockFuncs = [ | var sockFuncs = [ | ||||||
|   'address' |   'address' | ||||||
| , 'destroy' | , 'destroy' | ||||||
| @ -383,11 +333,10 @@ var sockFuncs = [ | |||||||
| , 'setNoDelay' | , 'setNoDelay' | ||||||
| , 'setTimeout' | , 'setTimeout' | ||||||
| ]; | ]; | ||||||
| */ |  | ||||||
| // Unlike Packer.Stream.create this should handle all of the events needed to make everything work.
 | // Unlike Packer.Stream.create this should handle all of the events needed to make everything work.
 | ||||||
| Packer.wrapSocket = function(socket) { | Packer.wrapSocket = function (socket) { | ||||||
|   // node v10.2+ doesn't need a workaround for  https://github.com/nodejs/node/issues/8854
 |   // node v10.2+ doesn't need a workaround for  https://github.com/nodejs/node/issues/8854
 | ||||||
| 	addressNames.forEach(function(name) { |   addressNames.forEach(function (name) { | ||||||
|     Object.defineProperty(socket, name, { |     Object.defineProperty(socket, name, { | ||||||
|       enumerable: false, |       enumerable: false, | ||||||
|       configurable: true, |       configurable: true, | ||||||
| @ -459,7 +408,7 @@ function MyTransform(options) { | |||||||
| } | } | ||||||
| util.inherits(MyTransform, Transform); | util.inherits(MyTransform, Transform); | ||||||
| 
 | 
 | ||||||
| MyTransform.prototype._transform = function(data, encoding, callback) { | MyTransform.prototype._transform = function (data, encoding, callback) { | ||||||
|   var address = this.__my_addr; |   var address = this.__my_addr; | ||||||
| 
 | 
 | ||||||
|   address.service = address.service || this.__my_service; |   address.service = address.service || this.__my_service; | ||||||
| @ -471,11 +420,11 @@ MyTransform.prototype._transform = function(data, encoding, callback) { | |||||||
| 
 | 
 | ||||||
| Packer.Stream = {}; | Packer.Stream = {}; | ||||||
| var Dup = { | var Dup = { | ||||||
| 	write: function(chunk, encoding, cb) { |   write: function (chunk, encoding, cb) { | ||||||
|     //console.log('_write', chunk.byteLength);
 |     //console.log('_write', chunk.byteLength);
 | ||||||
|     this.__my_socket.write(chunk, encoding, cb); |     this.__my_socket.write(chunk, encoding, cb); | ||||||
| 	}, |   } | ||||||
| 	read: function(size) { | , read: function (size) { | ||||||
|     //console.log('_read');
 |     //console.log('_read');
 | ||||||
|     var x = this.__my_socket.read(size); |     var x = this.__my_socket.read(size); | ||||||
|     if (x) { |     if (x) { | ||||||
| @ -484,7 +433,7 @@ var Dup = { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| Packer.Stream.create = function(socket) { | Packer.Stream.create = function (socket) { | ||||||
|   if (!Packer.Stream.warned) { |   if (!Packer.Stream.warned) { | ||||||
|     console.warn('`Stream.create` deprecated, use `wrapSocket` instead'); |     console.warn('`Stream.create` deprecated, use `wrapSocket` instead'); | ||||||
|     Packer.Stream.warned = true; |     Packer.Stream.warned = true; | ||||||
| @ -518,7 +467,7 @@ Packer.Stream.create = function(socket) { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Packer.Transform = {}; | Packer.Transform = {}; | ||||||
| Packer.Transform.create = function(opts) { | Packer.Transform.create = function (opts) { | ||||||
|   // Note: service refers to the port that the incoming request was from,
 |   // Note: service refers to the port that the incoming request was from,
 | ||||||
|   // if known (smtps, smtp, https, http, etc)
 |   // if known (smtps, smtp, https, http, etc)
 | ||||||
|   // { address: '127.0.0.1', service: 'https' }
 |   // { address: '127.0.0.1', service: 'https' }
 | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "proxy-packer", |   "name": "proxy-packer", | ||||||
| 	"version": "2.0.4", |   "version": "1.5.0", | ||||||
|   "description": "A strategy for packing and unpacking a proxy stream (i.e. packets through a tunnel). Handles multiplexed and tls connections. Used by telebit and telebitd.", |   "description": "A strategy for packing and unpacking a proxy stream (i.e. packets through a tunnel). Handles multiplexed and tls connections. Used by telebit and telebitd.", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  | |||||||
| @ -1,11 +1,10 @@ | |||||||
| { | { "version": 1 | ||||||
| 	"version": 1, | , "address": { | ||||||
| 	"address": { |     "family": "IPv4" | ||||||
| 		"family": "IPv4", |   , "address": "127.0.1.1" | ||||||
| 		"address": "127.0.1.1", |   , "port": 4321 | ||||||
| 		"port": 4321, |   , "service": "https" | ||||||
| 		"service": "https", |   , "serviceport": 443 | ||||||
| 		"serviceport": 443 |   } | ||||||
| 	}, | , "filepath": "./sni.hello.bin" | ||||||
| 	"filepath": "./sni.hello.bin" |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										58
									
								
								test/pack.js
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								test/pack.js
									
									
									
									
									
								
							| @ -1,31 +1,28 @@ | |||||||
| (function() { | ;(function () { | ||||||
| 	'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| 	var fs = require('fs'); | var fs = require('fs'); | ||||||
| 	var infile = process.argv[2]; | var infile = process.argv[2]; | ||||||
| 	var outfile = process.argv[3]; | var outfile = process.argv[3]; | ||||||
| 	var sni = require('sni'); | var sni = require('sni'); | ||||||
| 
 | 
 | ||||||
| 	if (!infile || !outfile) { | if (!infile || !outfile) { | ||||||
| 		console.error('Usage:'); |   console.error("Usage:"); | ||||||
| 		console.error('node test/pack.js test/input.json test/output.bin'); |   console.error("node test/pack.js test/input.json test/output.bin"); | ||||||
|   process.exit(1); |   process.exit(1); | ||||||
|   return; |   return; | ||||||
| 	} | } | ||||||
| 
 | 
 | ||||||
| 	var path = require('path'); | var path = require('path'); | ||||||
| 	var json = JSON.parse(fs.readFileSync(infile, 'utf8')); | var json = JSON.parse(fs.readFileSync(infile, 'utf8')); | ||||||
| 	var data = require('fs').readFileSync( | var data = require('fs').readFileSync(path.resolve(path.dirname(infile), json.filepath), null); | ||||||
| 		path.resolve(path.dirname(infile), json.filepath), | var Packer = require('../index.js'); | ||||||
| 		null |  | ||||||
| 	); |  | ||||||
| 	var Packer = require('../index.js'); |  | ||||||
| 
 | 
 | ||||||
| 	var servername = sni(data); | var servername = sni(data); | ||||||
| 	var m = data.toString().match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im); | var m = data.toString().match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im); | ||||||
| 	var hostname = ((m && m[1].toLowerCase()) || '').split(':')[0]; | var hostname = (m && m[1].toLowerCase() || '').split(':')[0]; | ||||||
| 
 | 
 | ||||||
| 	/* | /* | ||||||
| function pack() { | function pack() { | ||||||
|   var version = json.version; |   var version = json.version; | ||||||
|   var address = json.address; |   var address = json.address; | ||||||
| @ -40,16 +37,9 @@ function pack() { | |||||||
| } | } | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| 	json.address.name = servername || hostname; | json.address.name = servername || hostname; | ||||||
| 	var buf = Packer.pack(json.address, data); | var buf = Packer.pack(json.address, data); | ||||||
| 	fs.writeFileSync(outfile, buf, null); | fs.writeFileSync(outfile, buf, null); | ||||||
| 	console.log( | console.log("wrote " + buf.byteLength + " bytes to '" + outfile + "' ('hexdump " + outfile + "' to inspect)"); | ||||||
| 		'wrote ' + | 
 | ||||||
| 			buf.byteLength + | }()); | ||||||
| 			" bytes to '" + |  | ||||||
| 			outfile + |  | ||||||
| 			"' ('hexdump " + |  | ||||||
| 			outfile + |  | ||||||
| 			"' to inspect)" |  | ||||||
| 	); |  | ||||||
| })(); |  | ||||||
|  | |||||||
							
								
								
									
										225
									
								
								test/parse.js
									
									
									
									
									
								
							
							
						
						
									
										225
									
								
								test/parse.js
									
									
									
									
									
								
							| @ -3,197 +3,87 @@ | |||||||
| var sni = require('sni'); | var sni = require('sni'); | ||||||
| var hello = require('fs').readFileSync(__dirname + '/sni.hello.bin'); | var hello = require('fs').readFileSync(__dirname + '/sni.hello.bin'); | ||||||
| var version = 1; | var version = 1; | ||||||
| function getAddress() { | var address = { | ||||||
| 	return { |   family: 'IPv4' | ||||||
| 		family: 'IPv4', | , address: '127.0.1.1' | ||||||
| 		address: '127.0.1.1', | , port: 4321 | ||||||
| 		port: 4321, | , service: 'foo-https' | ||||||
| 		service: 'foo-https', | , serviceport: 443 | ||||||
| 		serviceport: 443, | , name: 'foo-pokemap.hellabit.com' | ||||||
| 		name: 'foo-pokemap.hellabit.com' | }; | ||||||
| 	}; | var header = address.family + ',' + address.address + ',' + address.port + ',' + hello.byteLength | ||||||
| } |   + ',' + (address.service || '') + ',' + (address.serviceport || '') + ',' + (address.name || '') | ||||||
| var addr = getAddress(); |   ; | ||||||
| var connectionHeader = |  | ||||||
| 	addr.family + |  | ||||||
| 	',' + |  | ||||||
| 	addr.address + |  | ||||||
| 	',' + |  | ||||||
| 	addr.port + |  | ||||||
| 	',0,connection,' + |  | ||||||
| 	(addr.serviceport || '') + |  | ||||||
| 	',' + |  | ||||||
| 	(addr.name || '') + |  | ||||||
| 	',' + |  | ||||||
| 	(addr.service || ''); |  | ||||||
| var header = |  | ||||||
| 	addr.family + |  | ||||||
| 	',' + |  | ||||||
| 	addr.address + |  | ||||||
| 	',' + |  | ||||||
| 	addr.port + |  | ||||||
| 	',' + |  | ||||||
| 	hello.byteLength + |  | ||||||
| 	',' + |  | ||||||
| 	(addr.service || '') + |  | ||||||
| 	',' + |  | ||||||
| 	(addr.serviceport || '') + |  | ||||||
| 	',' + |  | ||||||
| 	(addr.name || ''); |  | ||||||
| var endHeader = |  | ||||||
| 	addr.family + |  | ||||||
| 	',' + |  | ||||||
| 	addr.address + |  | ||||||
| 	',' + |  | ||||||
| 	addr.port + |  | ||||||
| 	',0,end,' + |  | ||||||
| 	(addr.serviceport || '') + |  | ||||||
| 	',' + |  | ||||||
| 	(addr.name || ''); |  | ||||||
| var buf = Buffer.concat([ | var buf = Buffer.concat([ | ||||||
| 	Buffer.from([255 - version, connectionHeader.length]), |   Buffer.from([ 255 - version, header.length ]) | ||||||
| 	Buffer.from(connectionHeader), | , Buffer.from(header) | ||||||
| 	Buffer.from([255 - version, header.length]), | , hello | ||||||
| 	Buffer.from(header), |  | ||||||
| 	hello, |  | ||||||
| 	Buffer.from([255 - version, endHeader.length]), |  | ||||||
| 	Buffer.from(endHeader) |  | ||||||
| ]); | ]); | ||||||
| var services = { ssh: 22, http: 4080, https: 8443 }; | var services = { 'ssh': 22, 'http': 4080, 'https': 8443 }; | ||||||
| var clients = {}; | var clients = {}; | ||||||
| var count = 0; | var count = 0; | ||||||
| var packer = require('../'); | var packer = require('../'); | ||||||
| var machine = packer.create({ | var machine = packer.create({ | ||||||
| 	onconnection: function(tun) { |   onmessage: function (tun) { | ||||||
| 		console.info(''); |  | ||||||
| 		if (!tun.service || 'connection' === tun.service) { |  | ||||||
| 			throw new Error('missing service: ' + JSON.stringify(tun)); |  | ||||||
| 		} |  | ||||||
| 		console.info('[onConnection]'); |  | ||||||
| 		count += 1; |  | ||||||
| 	}, |  | ||||||
| 	onmessage: function(tun) { |  | ||||||
| 		//console.log('onmessage', tun);
 |  | ||||||
|     var id = tun.family + ',' + tun.address + ',' + tun.port; |     var id = tun.family + ',' + tun.address + ',' + tun.port; | ||||||
|     var service = 'https'; |     var service = 'https'; | ||||||
|     var port = services[service]; |     var port = services[service]; | ||||||
|     var servername = sni(tun.data); |     var servername = sni(tun.data); | ||||||
| 
 | 
 | ||||||
| 		console.info( |     console.log(''); | ||||||
| 			'[onMessage]', |     console.log('[onMessage]'); | ||||||
| 			service, |  | ||||||
| 			port, |  | ||||||
| 			servername, |  | ||||||
| 			tun.data.byteLength |  | ||||||
| 		); |  | ||||||
|     if (!tun.data.equals(hello)) { |     if (!tun.data.equals(hello)) { | ||||||
| 			throw new Error( |       throw new Error("'data' packet is not equal to original 'hello' packet"); | ||||||
| 				"'data' packet is not equal to original 'hello' packet" |  | ||||||
| 			); |  | ||||||
|     } |     } | ||||||
| 		//console.log('all', tun.data.byteLength, 'bytes are equal');
 |     console.log('all', tun.data.byteLength, 'bytes are equal'); | ||||||
| 		//console.log('src:', tun.family, tun.address + ':' + tun.port + ':' + tun.serviceport);
 |     console.log('src:', tun.family, tun.address + ':' + tun.port + ':' + tun.serviceport); | ||||||
| 		//console.log('dst:', 'IPv4 127.0.0.1:' + port);
 |     console.log('dst:', 'IPv4 127.0.0.1:' + port); | ||||||
| 
 | 
 | ||||||
|     if (!clients[id]) { |     if (!clients[id]) { | ||||||
|       clients[id] = true; |       clients[id] = true; | ||||||
|       if (!servername) { |       if (!servername) { | ||||||
|         throw new Error("no servername found for '" + id + "'"); |         throw new Error("no servername found for '" + id + "'"); | ||||||
|       } |       } | ||||||
| 			//console.log("servername: '" + servername + "'", tun.name);
 |       console.log("servername: '" + servername + "'", tun.name); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     count += 1; |     count += 1; | ||||||
| 	}, |   } | ||||||
| 	onerror: function() { | , onerror: function () { | ||||||
| 		throw new Error('Did not expect onerror'); |     throw new Error("Did not expect onerror"); | ||||||
| 	}, |   } | ||||||
| 	onend: function() { | , onend: function () { | ||||||
| 		console.info('[onEnd]'); |     throw new Error("Did not expect onend"); | ||||||
| 		count += 1; |  | ||||||
|   } |   } | ||||||
| }); | }); | ||||||
| 
 | var packed = packer.pack(address, hello); | ||||||
| var packts, packed; |  | ||||||
| 
 |  | ||||||
| packts = []; |  | ||||||
| packts.push(packer.packHeader(getAddress(), null, 'connection')); |  | ||||||
| //packts.push(packer.pack(address, hello));
 |  | ||||||
| packts.push(packer.packHeader(getAddress(), hello)); |  | ||||||
| packts.push(hello); |  | ||||||
| packts.push(packer.packHeader(getAddress(), null, 'end')); |  | ||||||
| packed = Buffer.concat(packts); |  | ||||||
| 
 | 
 | ||||||
| if (!packed.equals(buf)) { | if (!packed.equals(buf)) { | ||||||
| 	console.error(''); |  | ||||||
|   console.error(buf.toString('hex') === packed.toString('hex')); |   console.error(buf.toString('hex') === packed.toString('hex')); | ||||||
| 	console.error(''); |  | ||||||
| 	console.error('auto-packed:'); |  | ||||||
|   console.error(packed.toString('hex'), packed.byteLength); |   console.error(packed.toString('hex'), packed.byteLength); | ||||||
| 	console.error(''); |  | ||||||
| 	console.error('hand-packed:'); |  | ||||||
|   console.error(buf.toString('hex'), buf.byteLength); |   console.error(buf.toString('hex'), buf.byteLength); | ||||||
| 	console.error(''); |   throw new Error("packer did not pack as expected"); | ||||||
| 	throw new Error('packer (new) did not pack as expected'); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| packts = []; |  | ||||||
| packts.push(packer.pack(getAddress(), null, 'connection')); |  | ||||||
| packts.push(packer.pack(getAddress(), hello)); |  | ||||||
| //packts.push(packer.packHeader(getAddress(), hello));
 |  | ||||||
| //packts.push(hello);
 |  | ||||||
| packts.push(packer.pack(getAddress(), null, 'end')); |  | ||||||
| packed = Buffer.concat(packts); |  | ||||||
| 
 | 
 | ||||||
| // XXX TODO REMOVE
 | console.log(''); | ||||||
| //
 |  | ||||||
| // Nasty fix for short-term backwards-compat
 |  | ||||||
| //
 |  | ||||||
| // In the old way of doing things we always have at least one byte
 |  | ||||||
| // of data (due to a parser bug which has now been fixed) and so
 |  | ||||||
| // there are two strings padded with a space which gives the
 |  | ||||||
| // data a length of 1 rather than 0
 |  | ||||||
| //
 |  | ||||||
| // Here all four of those instances are replaced, but it requires
 |  | ||||||
| // maching a few things on either side.
 |  | ||||||
| //
 |  | ||||||
| // Only 6 bytes are changed - two 1 => 0, four ' ' => ''
 |  | ||||||
| var hex = packed |  | ||||||
| 	.toString('hex') |  | ||||||
| 	//.replace(/2c313939/, '2c30')
 |  | ||||||
| 	.replace(/32312c312c636f/, '32312c302c636f') |  | ||||||
| 	.replace(/3332312c312c656e64/, '3332312c302c656e64') |  | ||||||
| 	.replace(/7320/, '73') |  | ||||||
| 	.replace(/20$/, ''); |  | ||||||
| if (hex !== buf.toString('hex')) { |  | ||||||
| 	console.error(''); |  | ||||||
| 	console.error(buf.toString('hex') === hex); |  | ||||||
| 	console.error(''); |  | ||||||
| 	console.error('auto-packed:'); |  | ||||||
| 	console.error(hex, packed.byteLength); |  | ||||||
| 	console.error(''); |  | ||||||
| 	console.error('hand-packed:'); |  | ||||||
| 	console.error(buf.toString('hex'), buf.byteLength); |  | ||||||
| 	console.error(''); |  | ||||||
| 	throw new Error('packer (old) did not pack as expected'); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| console.info(''); |  | ||||||
| 
 | 
 | ||||||
| // full message in one go
 | // full message in one go
 | ||||||
| // 223 = 2 + 22 + 199
 | // 223 = 2 + 22 + 199
 | ||||||
| console.info('[WHOLE BUFFER]', 2, header.length, hello.length, buf.byteLength); | console.log('[WHOLE BUFFER]', 2, header.length, hello.length, buf.byteLength); | ||||||
| clients = {}; | clients = {}; | ||||||
| machine.fns.addChunk(buf); | machine.fns.addChunk(buf); | ||||||
| console.info(''); | console.log(''); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| // messages one byte at a time
 | // messages one byte at a time
 | ||||||
| console.info('[BYTE-BY-BYTE BUFFER]', 1); | console.log('[BYTE-BY-BYTE BUFFER]', 1); | ||||||
| clients = {}; | clients = {}; | ||||||
| buf.forEach(function(byte) { | buf.forEach(function (byte) { | ||||||
| 	machine.fns.addChunk(Buffer.from([byte])); |   machine.fns.addChunk(Buffer.from([ byte ])); | ||||||
| }); | }); | ||||||
| console.info(''); | console.log(''); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| // split messages in overlapping thirds
 | // split messages in overlapping thirds
 | ||||||
| // 0-2      (2)
 | // 0-2      (2)
 | ||||||
| @ -202,27 +92,26 @@ console.info(''); | |||||||
| // 223-225  (2)
 | // 223-225  (2)
 | ||||||
| // 225-247  (22)
 | // 225-247  (22)
 | ||||||
| // 247-446  (199)
 | // 247-446  (199)
 | ||||||
| buf = Buffer.concat([buf, buf]); | buf = Buffer.concat([ buf, buf ]); | ||||||
| console.info('[OVERLAPPING BUFFERS]', buf.length); | console.log('[OVERLAPPING BUFFERS]', buf.length); | ||||||
| clients = {}; | clients = {}; | ||||||
| [ | [ buf.slice(0, 7)                 // version + header
 | ||||||
| 	buf.slice(0, 7), // version + header
 | , buf.slice(7, 14)                // header
 | ||||||
| 	buf.slice(7, 14), // header
 | , buf.slice(14, 21)               // header
 | ||||||
| 	buf.slice(14, 21), // header
 | , buf.slice(21, 28)               // header + body
 | ||||||
| 	buf.slice(21, 28), // header + body
 | , buf.slice(28, 217)              // body
 | ||||||
| 	buf.slice(28, 217), // body
 | , buf.slice(217, 224)             // body + version
 | ||||||
| 	buf.slice(217, 224), // body + version
 | , buf.slice(224, 238)             // version + header
 | ||||||
| 	buf.slice(224, 238), // version + header
 | , buf.slice(238, buf.byteLength)  // header + body
 | ||||||
| 	buf.slice(238, buf.byteLength) // header + body
 | ].forEach(function (buf) { | ||||||
| ].forEach(function(buf) { |  | ||||||
|   machine.fns.addChunk(Buffer.from(buf)); |   machine.fns.addChunk(Buffer.from(buf)); | ||||||
| }); | }); | ||||||
| console.info(''); | console.log(''); | ||||||
| 
 | 
 | ||||||
| process.on('exit', function() { | process.on('exit', function () { | ||||||
| 	if (count !== 12) { |   if (count !== 4) { | ||||||
| 		throw new Error('should have delivered 12 messages, not ' + count); |     throw new Error("should have delivered 4 messages, not", count); | ||||||
|   } |   } | ||||||
| 	console.info('TESTS PASS'); |   console.log('TESTS PASS'); | ||||||
| 	console.info(''); |   console.log(''); | ||||||
| }); | }); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user