├── .gitignore ├── .travis.yml ├── README.md ├── example └── simple-load-balancer.js ├── lib ├── tcp-proxy.js └── tcp-proxy │ └── index.js ├── package.json └── test └── simple-proxy-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by http://gitignore.io 2 | 3 | ### Node ### 4 | lib-cov 5 | *.seed 6 | *.log 7 | *.csv 8 | *.dat 9 | *.out 10 | *.pid 11 | *.gz 12 | 13 | pids 14 | logs 15 | results 16 | 17 | npm-debug.log 18 | node_modules 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tcp-proxy 2 | 3 | [![build status](https://secure.travis-ci.org/jcrugzz/tcp-proxy.png)](http://travis-ci.org/jcrugzz/tcp-proxy) 4 | 5 | Exactly what you would expect, a simple tcp proxy written in node. Inspiration 6 | from [`node-http-proxy`][http-proxy]. 7 | 8 | ## Work in Progress 9 | 10 | ## Example 11 | 12 | Simple tcp proxy 13 | 14 | ```js 15 | 16 | var tcpProxy = require('tcp-proxy'); 17 | 18 | var server = tcpProxy.createServer({ 19 | target: { 20 | host: '127.0.0.1', 21 | port: 9000 22 | } 23 | }); 24 | 25 | server.listen(8000); 26 | 27 | ``` 28 | 29 | ## API 30 | 31 | 32 | 33 | [http-proxy]: https://github.com/nodejitsu/node-http-proxy 34 | -------------------------------------------------------------------------------- /example/simple-load-balancer.js: -------------------------------------------------------------------------------- 1 | var net = require('net'); 2 | var TcpProxy = require('../'); 3 | 4 | var targets = [ 5 | { 6 | host: 'localhost', 7 | port: 8001 8 | }, 9 | { 10 | host: 'localhost', 11 | port: 8002 12 | } 13 | ]; 14 | 15 | var proxies = targets.map(function (target) { 16 | return new TcpProxy({ 17 | target: target 18 | }); 19 | }); 20 | 21 | var nextProxy = function () { 22 | var proxy = proxies.shift(); 23 | proxies.push(proxy); 24 | return proxy; 25 | }; 26 | 27 | var server = net.createServer(function(socket) { 28 | nextProxy().proxy(socket); 29 | }); 30 | 31 | server.listen(8000); 32 | -------------------------------------------------------------------------------- /lib/tcp-proxy.js: -------------------------------------------------------------------------------- 1 | var net = require('net'), 2 | tls = require('tls'), 3 | tcpProxy = require('./tcp-proxy/'); 4 | 5 | module.exports = tcpProxy; 6 | 7 | module.exports.createServer = 8 | module.exports.createProxyServer = function createServer(options) { 9 | var server = options.ssl 10 | ? tls.createServer(options.ssl, requestHandler) 11 | : net.createServer(requestHandler); 12 | 13 | var proxy = tcpProxy(options); 14 | proxy.on('error', server.emit.bind(server, 'error')); 15 | 16 | function requestHandler(socket) { 17 | proxy.proxy(socket, options); 18 | } 19 | 20 | return server; 21 | }; 22 | 23 | 24 | -------------------------------------------------------------------------------- /lib/tcp-proxy/index.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | net = require('net'), 3 | tls = require('tls'), 4 | EventEmitter = require('eventemitter3'), 5 | stream = require('stream'); 6 | 7 | var Duplex = stream.Duplex; 8 | 9 | module.exports = TcpProxy; 10 | 11 | util.inherits(TcpProxy, EventEmitter); 12 | 13 | function TcpProxy (options) { 14 | EventEmitter.call(this); 15 | if (!(this instanceof TcpProxy)) { return new TcpProxy(options) } 16 | // 17 | // Remark: lulz damnit we are only an eventEmitter to propagate errors, 18 | // I JUST WANT ONE FUNCTION WITH EE FANCINESS 19 | // 20 | 21 | }; 22 | 23 | TcpProxy.prototype.proxy = function (socket, options) { 24 | this.socket = socket; 25 | 26 | options.target = options.target || this.target; 27 | // 28 | // TODO: Make this depend on whether we need to proxy as TLS to the backend or not 29 | // So essentially this should be more variable 30 | // 31 | this.proxySock = options.ssl 32 | ? tls.connect(options.ssl, options.target) 33 | : net.connect(options.target); 34 | 35 | // 36 | // Remark: is this stream going to emit the error or is the source socket 37 | // emitting it when it fails to proxy? 38 | // 39 | // I am assuming there can probably be errors from either stream, the proxy 40 | // stream may be the only case that we want to attempt a reconnect. 41 | // 42 | // TODO: retry should exist 43 | // 44 | this.proxySock.on('error', this.emit.bind(this, 'error')); 45 | this.socket.on('error', this.emit.bind(this, 'error')); 46 | 47 | this.proxySock.pipe(this.socket).pipe(this.proxySock); 48 | 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tcp-proxy", 3 | "description": "A simple TCP proxy using node.js based on the work of node-http-proxy", 4 | "version": "0.0.1", 5 | "author": "Jarrett Cruger ", 6 | "repository": { 7 | "url": "git://github.com/jcrugzz/tcp-proxy.git" 8 | }, 9 | "main": "./lib/tcp-proxy.js", 10 | "scripts": { 11 | "test": "tap test/*.js" 12 | }, 13 | "engines": { 14 | "node": "0.10.x" 15 | }, 16 | "dependencies": { 17 | "uuid": "~1.4.1", 18 | "eventemitter3": "0.0.0" 19 | }, 20 | "devDependencies": { 21 | "tap": "~0.4.4", 22 | "concat-stream": "~1.0.1" 23 | }, 24 | "license": "MIT" 25 | } 26 | -------------------------------------------------------------------------------- /test/simple-proxy-test.js: -------------------------------------------------------------------------------- 1 | var net = require('net'), 2 | concat = require('concat-stream'), 3 | test = require('tap').test; 4 | 5 | var tcpProxy = require('../'); 6 | 7 | var proxyPort = 9000, 8 | serverPort = 9001; 9 | 10 | var data = 'Hello\n', 11 | target = { target: { host: '127.0.0.1', port: serverPort }}; 12 | 13 | test('test a simple proxy', function (t) { 14 | t.plan(3); 15 | 16 | var server, 17 | proxyServer, 18 | socket; 19 | 20 | function cleanup() { 21 | server.close(); 22 | proxyServer.close(); 23 | socket.destroy(); 24 | 25 | t.pass('cleanup success'); 26 | } 27 | 28 | function onError(err) { 29 | t.fail(err); 30 | cleanup(); 31 | } 32 | 33 | server = net.createServer(function (sock) { 34 | sock.on('data', function (chunk) { 35 | t.equals(''+chunk, data, 'server recieved data through proxy'); 36 | sock.write(data); 37 | }); 38 | }); 39 | 40 | server.on('error', onError); 41 | server.listen(serverPort, startProxy); 42 | function startProxy() { 43 | proxyServer = tcpProxy.createServer(target); 44 | console.log('starting proxy'); 45 | proxyServer.on('error', onError) 46 | proxyServer.listen(proxyPort, runTest); 47 | } 48 | 49 | function runTest() { 50 | socket = net.connect(proxyPort); 51 | console.log('writing data'); 52 | socket.write(data); 53 | socket.on('data', function (d) { 54 | t.equals(''+d, data, 'client recieved data from server through proxy'); 55 | cleanup(); 56 | }); 57 | 58 | } 59 | }); 60 | --------------------------------------------------------------------------------