From e496239c3d86102f9a800ac2e322e14d12213936 Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Tue, 18 Mar 2014 16:56:17 -0400 Subject: [PATCH 01/13] added socks5 client dependency --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ee9479..492a47c 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,8 @@ "browserify-bignum": "git://github.com/maraoz/browserify-bignum.git", "browserify-buffertools": "~1.0.2", "brfs": "~1.0.0", - "uglifyify": "~1.2.3" + "uglifyify": "~1.2.3", + "socks5-client": "^0.3.4" }, "devDependencies": { "grunt-contrib-watch": "~0.5.3", From ebec07c050a0dee3587e336a89637b81980d88f0 Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Wed, 19 Mar 2014 16:11:47 -0400 Subject: [PATCH 02/13] added a seedlist class and example for connecting over tor --- SeedList.js | 47 ++++++++++++++++++++++++++++++++++++++++++++ config.js | 2 +- examples/TorProxy.js | 33 +++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 SeedList.js create mode 100644 examples/TorProxy.js diff --git a/SeedList.js b/SeedList.js new file mode 100644 index 0000000..b90ad88 --- /dev/null +++ b/SeedList.js @@ -0,0 +1,47 @@ +'use strict'; +var imports = require('soop').imports(); +var parent = imports.parent || require('events').EventEmitter; +var EventEmitter = require('events').EventEmitter; +var dns = require('dns'); +var inherits = require('util').inherits; + +function SeedList(options) { + this.options = options || {}; + this.sources = [ + 'dnsseed.bluematt.me', + 'dnsseed.bitcoin.dashjr.org', + 'seed.bitcoin.sipa.be', + 'seed.bitcoinstats.com', + 'bitseed.xf2.org' + ]; + this.source = this.options.source || this.sources[0]; + this.seeds = []; + this.find() +}; + +inherits(SeedList, EventEmitter); + +SeedList.prototype.find = function() { + var self = this; + dns.resolve(self.source, function(err, seeds) { + if (err) { + var index = self.sources.indexOf(self.source); + if (index !== -1) { + index++; + if (!self.sources[index]) { + return self.emit('seedsNotFound'); + } + else { + self.source = self.sources[index]; + } + self.find(); + } + return self.emit('error', err); + } + self.seeds = self.seeds.concat(seeds); + self.emit('seedsFound', seeds); + }); + return self; +}; + +module.exports = require('soop')(SeedList); diff --git a/config.js b/config.js index aea295c..5833536 100644 --- a/config.js +++ b/config.js @@ -1,4 +1,4 @@ module.exports = { network: 'livenet', - logger: 'normal' // none, normal, debug + logger: 'debug' // none, normal, debug }; diff --git a/examples/TorProxy.js b/examples/TorProxy.js new file mode 100644 index 0000000..2603da9 --- /dev/null +++ b/examples/TorProxy.js @@ -0,0 +1,33 @@ +var Socks5Client = require('socks5-client'); +var Peer = require('../Peer'); +var Connection = require('../Connection'); +var SeedList = require('../SeedList') + +// start looking for a seed +var seedlist = new SeedList(); +// create a client socket proxied through +// tor's socks5 proxy +var client = new Socks5Client('127.0.0.1', 9050); + +// when we have a list of seeds... +seedlist.on('seedsFound', function(seeds) { + // use the first seed in list + var peer = new Peer(seeds[0], 8333); + var connection = new Connection(client, peer); + // open the connection to the seed + client.connect(peer.port, peer.host); + // always handle errors + connection.on('error', function(err) { + console.log(err); + }); +}); + +// failboat +seedlist.on('seedsNotFound', function() { + console.log('failed to find seeds :('); +}); + +// double failboat +seedlist.on('error', function(err) { + console.log('error:', err); +}); From 5cc98a459525300d626324ac3c7b264c4d3e66cb Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Wed, 19 Mar 2014 16:13:42 -0400 Subject: [PATCH 03/13] using soop for inheritance --- SeedList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SeedList.js b/SeedList.js index b90ad88..05ea63a 100644 --- a/SeedList.js +++ b/SeedList.js @@ -3,9 +3,9 @@ var imports = require('soop').imports(); var parent = imports.parent || require('events').EventEmitter; var EventEmitter = require('events').EventEmitter; var dns = require('dns'); -var inherits = require('util').inherits; function SeedList(options) { + SeedList.super(this, arguments); this.options = options || {}; this.sources = [ 'dnsseed.bluematt.me', @@ -19,7 +19,7 @@ function SeedList(options) { this.find() }; -inherits(SeedList, EventEmitter); +SeedList.parent = imports.parent || EventEmitter; SeedList.prototype.find = function() { var self = this; From ce0a240d6b5a0c90846ec601af2ea9d6f92a8c7d Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Wed, 19 Mar 2014 17:36:28 -0400 Subject: [PATCH 04/13] pointing socks5-client to gordon's fork --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 492a47c..363566c 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "browserify-buffertools": "~1.0.2", "brfs": "~1.0.0", "uglifyify": "~1.2.3", - "socks5-client": "^0.3.4" + "socks5-client": "git+https://github.com/gordonwritescode/socks5-client.git" }, "devDependencies": { "grunt-contrib-watch": "~0.5.3", From b23f3c808811978753e2ce2617330179419e41fd Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Fri, 4 Apr 2014 11:46:57 -0400 Subject: [PATCH 05/13] add support for connecting over tor, remove seedlist class (for now) --- Connection.js | 19 ++++++++++++++-- PeerManager.js | 4 ++-- SeedList.js | 47 --------------------------------------- examples/ConnectionTor.js | 32 ++++++++++++++++++++++++++ examples/TorProxy.js | 33 --------------------------- 5 files changed, 51 insertions(+), 84 deletions(-) delete mode 100644 SeedList.js create mode 100644 examples/ConnectionTor.js delete mode 100644 examples/TorProxy.js diff --git a/Connection.js b/Connection.js index f273ec3..8c6c589 100644 --- a/Connection.js +++ b/Connection.js @@ -10,6 +10,7 @@ var PROTOCOL_VERSION = 70000; var Binary = imports.Binary || require('binary'); var Put = imports.Put || require('bufferput'); var Buffers = imports.Buffers || require('buffers'); +var Socks5Client = imports.Socks5Client || require('socks5-client') require('./Buffers.monkey').patch(Buffers); var Block = require('./Block'); @@ -22,11 +23,19 @@ var nonce = util.generateNonce(); var BIP0031_VERSION = 60000; -function Connection(socket, peer) { +function Connection(socket, peer, opts) { Connection.super(this, arguments); + + this.options = opts || {}; + this.socket = socket; this.peer = peer; + // check for socks5 proxy options and construct a proxied socket + if (this.options.proxy) { + this.socket = new Socks5Client(opts.proxy.host, opts.proxy.port); + } + // A connection is considered "active" once we have received verack this.active = false; // The version incoming packages are interpreted as @@ -36,7 +45,7 @@ function Connection(socket, peer) { // The (claimed) height of the remote peer's block chain this.bestHeight = 0; // Is this an inbound connection? - this.inbound = !!socket.server; + this.inbound = !!this.socket.server; // Have we sent a getaddr on this connection? this.getaddr = false; @@ -54,6 +63,12 @@ function Connection(socket, peer) { } Connection.parent = imports.parent || require('events').EventEmitter; +Connection.prototype.open = function(callback) { + if (typeof callback === 'function') this.once('connect', callback); + this.socket.connect(this.peer.port, this.peer.host); + return this; +}; + Connection.prototype.setupHandlers = function () { this.socket.addListener('connect', this.handleConnect.bind(this)); this.socket.addListener('error', this.handleError.bind(this)); diff --git a/PeerManager.js b/PeerManager.js index c6e2029..67b6d43 100644 --- a/PeerManager.js +++ b/PeerManager.js @@ -95,8 +95,8 @@ PeerManager.prototype.connectTo = function(peer) { } }; -PeerManager.prototype.addConnection = function(socketConn, peer) { - var conn = new Connection(socketConn, peer); +PeerManager.prototype.addConnection = function(socketConn, peer, opts) { + var conn = new Connection(socketConn, peer, opts); this.connections.push(conn); this.emit('connection', conn); diff --git a/SeedList.js b/SeedList.js deleted file mode 100644 index 05ea63a..0000000 --- a/SeedList.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; -var imports = require('soop').imports(); -var parent = imports.parent || require('events').EventEmitter; -var EventEmitter = require('events').EventEmitter; -var dns = require('dns'); - -function SeedList(options) { - SeedList.super(this, arguments); - this.options = options || {}; - this.sources = [ - 'dnsseed.bluematt.me', - 'dnsseed.bitcoin.dashjr.org', - 'seed.bitcoin.sipa.be', - 'seed.bitcoinstats.com', - 'bitseed.xf2.org' - ]; - this.source = this.options.source || this.sources[0]; - this.seeds = []; - this.find() -}; - -SeedList.parent = imports.parent || EventEmitter; - -SeedList.prototype.find = function() { - var self = this; - dns.resolve(self.source, function(err, seeds) { - if (err) { - var index = self.sources.indexOf(self.source); - if (index !== -1) { - index++; - if (!self.sources[index]) { - return self.emit('seedsNotFound'); - } - else { - self.source = self.sources[index]; - } - self.find(); - } - return self.emit('error', err); - } - self.seeds = self.seeds.concat(seeds); - self.emit('seedsFound', seeds); - }); - return self; -}; - -module.exports = require('soop')(SeedList); diff --git a/examples/ConnectionTor.js b/examples/ConnectionTor.js new file mode 100644 index 0000000..f03bf9e --- /dev/null +++ b/examples/ConnectionTor.js @@ -0,0 +1,32 @@ +var Peer = require('../Peer'); +var Connection = require('../Connection'); + +// create a peer instance from a know peer +// (later we can use built-in peer discovery) +// to get a peer to connect to you can run: +// +// ~# dig dnsseed.bluematt.me +// +// (or use a different dns seed) +var peer = new Peer('108.13.10.109', 8333); + +// create a connection without an existing socket +// but specify a socks5 proxy to create a socket +// that's bound to that proxy in it's place +var connection = new Connection(null, peer, { + proxy: { host: '127.0.0.1', port: 9050 } +}); + +// open the connection +connection.open(); + +// you can listen for the connect event +connection.on('connect', function(data) { + // we are connected! + console.log('connected'); +}); + +connection.on('error', function(err) { + // boo! :( + console.log('poop'); +}); diff --git a/examples/TorProxy.js b/examples/TorProxy.js deleted file mode 100644 index 2603da9..0000000 --- a/examples/TorProxy.js +++ /dev/null @@ -1,33 +0,0 @@ -var Socks5Client = require('socks5-client'); -var Peer = require('../Peer'); -var Connection = require('../Connection'); -var SeedList = require('../SeedList') - -// start looking for a seed -var seedlist = new SeedList(); -// create a client socket proxied through -// tor's socks5 proxy -var client = new Socks5Client('127.0.0.1', 9050); - -// when we have a list of seeds... -seedlist.on('seedsFound', function(seeds) { - // use the first seed in list - var peer = new Peer(seeds[0], 8333); - var connection = new Connection(client, peer); - // open the connection to the seed - client.connect(peer.port, peer.host); - // always handle errors - connection.on('error', function(err) { - console.log(err); - }); -}); - -// failboat -seedlist.on('seedsNotFound', function() { - console.log('failed to find seeds :('); -}); - -// double failboat -seedlist.on('error', function(err) { - console.log('error:', err); -}); From 27191fc0ece7217c0d1b3a5517b6a88daa87ce82 Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Fri, 4 Apr 2014 11:49:11 -0400 Subject: [PATCH 06/13] point back to socks5-client upstream repo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 363566c..501f357 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "browserify-buffertools": "~1.0.2", "brfs": "~1.0.0", "uglifyify": "~1.2.3", - "socks5-client": "git+https://github.com/gordonwritescode/socks5-client.git" + "socks5-client": "~0.3.6" }, "devDependencies": { "grunt-contrib-watch": "~0.5.3", From 591d5fff401202305b37e881c461f85e33a24a57 Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Fri, 4 Apr 2014 11:53:05 -0400 Subject: [PATCH 07/13] set logger back to normal --- config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.js b/config.js index 5833536..aea295c 100644 --- a/config.js +++ b/config.js @@ -1,4 +1,4 @@ module.exports = { network: 'livenet', - logger: 'debug' // none, normal, debug + logger: 'normal' // none, normal, debug }; From 78edb3200eeeef5d092d9b44ab1a9a4978669622 Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Fri, 4 Apr 2014 12:45:38 -0400 Subject: [PATCH 08/13] change example to log actual error --- examples/ConnectionTor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ConnectionTor.js b/examples/ConnectionTor.js index f03bf9e..e41a77b 100644 --- a/examples/ConnectionTor.js +++ b/examples/ConnectionTor.js @@ -28,5 +28,5 @@ connection.on('connect', function(data) { connection.on('error', function(err) { // boo! :( - console.log('poop'); + console.log(err); }); From 529d26e052432cd2e62706d53c882b03b2d4adfa Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Wed, 9 Apr 2014 11:49:46 -0400 Subject: [PATCH 09/13] add missing comma to package.json deps --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 82098a7..d021292 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "browserify-bignum": "git://github.com/maraoz/browserify-bignum.git", "browserify-buffertools": "git://github.com/maraoz/browserify-buffertools.git", "brfs": "~1.0.0", - "socks5-client": "~0.3.6" + "socks5-client": "~0.3.6", "chai": "~1.9.0", "uglifyify": "~1.2.3" }, From e53a2341c3f00d8813d78f0c82afa737e8cdf1f1 Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Fri, 11 Apr 2014 13:56:37 -0400 Subject: [PATCH 10/13] updated connection tests --- package.json | 4 ++++ test/test.Connection.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/package.json b/package.json index d021292..3176ced 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,10 @@ { "name": "Ryan X. Charles", "email": "ryan@bitpay.com" + }, + { + "name": "Gordon Hall", + "email": "gordon@bitpay.com" } ], "keywords": [ diff --git a/test/test.Connection.js b/test/test.Connection.js index 8682973..f070993 100644 --- a/test/test.Connection.js +++ b/test/test.Connection.js @@ -23,6 +23,12 @@ describe('Connection', function() { var c = new Connection(mSocket, mPeer); should.exist(c); }); + it('should create a proxied socket if instructed', function() { + var c = new Connection(null, mPeer, { + proxy: { host: 'localhost', port: 9050 } + }); + should.exist(c.socket); + }); }); From a5ba4577873ac86623eec6432f92e666122ca65a Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Fri, 11 Apr 2014 14:05:53 -0400 Subject: [PATCH 11/13] update example to discover a peer instead of hardcoding arbitrary IP --- examples/ConnectionTor.js | 49 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/examples/ConnectionTor.js b/examples/ConnectionTor.js index e41a77b..aa006f6 100644 --- a/examples/ConnectionTor.js +++ b/examples/ConnectionTor.js @@ -1,32 +1,27 @@ var Peer = require('../Peer'); var Connection = require('../Connection'); +var dns = require('dns'); -// create a peer instance from a know peer -// (later we can use built-in peer discovery) -// to get a peer to connect to you can run: -// -// ~# dig dnsseed.bluematt.me -// -// (or use a different dns seed) -var peer = new Peer('108.13.10.109', 8333); +// get a peer from dns seed +dns.resolve('dnsseed.bluematt.me', function(err, seeds) { + // use the first peer + var peer = new Peer(seeds[0], 8333); + + // create a connection without an existing socket + // but specify a socks5 proxy to create a socket + // that's bound to that proxy in it's place + var connection = new Connection(null, peer, { + proxy: { host: '127.0.0.1', port: 9050 } + }); + + connection.open(); + + connection.on('connect', function(data) { + console.log('connected through socks5!'); + }); + + connection.on('error', function(err) { + console.log(err); + }); -// create a connection without an existing socket -// but specify a socks5 proxy to create a socket -// that's bound to that proxy in it's place -var connection = new Connection(null, peer, { - proxy: { host: '127.0.0.1', port: 9050 } -}); - -// open the connection -connection.open(); - -// you can listen for the connect event -connection.on('connect', function(data) { - // we are connected! - console.log('connected'); -}); - -connection.on('error', function(err) { - // boo! :( - console.log(err); }); From 7b9e2e7b4911439d8782bf97927219cff918f9ff Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Fri, 11 Apr 2014 14:12:00 -0400 Subject: [PATCH 12/13] remove duplicate dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index c54644d..a6917ab 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "commander": "=2.1.0", "browserify-bignum": "git://github.com/maraoz/browserify-bignum.git", "browserify-buffertools": "git://github.com/maraoz/browserify-buffertools.git", - "brfs": "~1.0.0", "socks5-client": "~0.3.6", "brfs": "=1.0.0", "chai": "=1.9.1", From a89b51d5aab7a2a248194c4f4ae0203a6eb54e67 Mon Sep 17 00:00:00 2001 From: Gordon Hall Date: Tue, 15 Apr 2014 10:30:41 -0400 Subject: [PATCH 13/13] requiring socks5 client conditionally from connection constructor --- Connection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Connection.js b/Connection.js index a9ff23d..27a4fb6 100644 --- a/Connection.js +++ b/Connection.js @@ -10,7 +10,6 @@ var PROTOCOL_VERSION = 70000; var Binary = imports.Binary || require('binary'); var Put = imports.Put || require('bufferput'); var Buffers = imports.Buffers || require('buffers'); -var Socks5Client = imports.Socks5Client || require('socks5-client') require('./Buffers.monkey').patch(Buffers); var Block = require('./Block'); @@ -33,6 +32,7 @@ function Connection(socket, peer, opts) { // check for socks5 proxy options and construct a proxied socket if (this.options.proxy) { + var Socks5Client = imports.Socks5Client || require('socks5-client'); this.socket = new Socks5Client(opts.proxy.host, opts.proxy.port); }