diff --git a/README.md b/README.md index 8fcab35..0847d94 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,79 @@ # holepunch -A node.js library and cli for using UPnP SSDP +A node.js library (api) and command (cli) for using UPnP SSDP and ZeroConf (Bonjour) NAT-PMP to make home and office devices and services Internet-accessible. ## Progress -in development +it now works :-) + +still in development ```bash +git clone git@github.com:Daplie/holepunch.git + +pushd holepunch + node bin/holepunch.js --debug ``` +## Install + +**Commandline Tool** +```bash +npm install --global holepunch +``` + +**node.js Library** +``` +npm install --save holepunch +``` + +## Commandline (CLI) + +```bash +holepunch --help +``` + +``` +holepunch --plain-ports 80,65080 --tls-ports 443,65443 +``` + +TODO `--prebound-ports 22` + +``` +Usage: + holepunch.js [OPTIONS] [ARGS] + +Options: + --debug BOOLEAN show traces and logs + + --plain-ports STRING Port numbers to test with plaintext loopback. + (default: 65080) + (formats: ,) + + --tls-ports STRING Port numbers to test with tls loopback. + (default: null) + + --ipify-urls STRING Comma separated list of URLs to test for external ip. + (default: api.ipify.org) + + --protocols STRING Comma separated list of ip mapping protocols. + (default: none,upnp,pmp) + + --rvpn-configs STRING Comma separated list of Reverse VPN config files in + the order they should be tried. (default: null) + + -h, --help Display help and usage details +``` + +## API + +```javascript +var punch = require('holepunch'); +``` + # License MPL-2.0 diff --git a/bin/holepunch.js b/bin/holepunch.js index 756c14b..aa45d5e 100755 --- a/bin/holepunch.js +++ b/bin/holepunch.js @@ -71,7 +71,8 @@ cli.main(function(_, options) { } return hp.create(args).then(function () { - console.log('wishing wanting waiting'); - //process.exit(0); + //console.log('[HP] wishing wanting waiting'); + console.log('complete, exiting'); + process.exit(0); }); }); diff --git a/examples/upnp-ssdp-igd-discovery.js b/examples/upnp-ssdp-igd-discovery.js index 0ee4065..72682c6 100644 --- a/examples/upnp-ssdp-igd-discovery.js +++ b/examples/upnp-ssdp-igd-discovery.js @@ -41,7 +41,7 @@ function createSocket() { }); socket.on('message', function (chunk, info) { - var message = chunk.toString(); + var message = chunk.toString('utf8'); console.log('[MESSAGE RECEIVED]'); console.log(info); diff --git a/lib/index.js b/lib/index.js index e333485..806b97e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -14,7 +14,7 @@ module.exports.create = function (args) { if (args.debug) { console.log('[HP] create servers'); - console.log(servers); + //console.log(servers); } function getExternalIps() { @@ -63,8 +63,8 @@ module.exports.create = function (args) { return portInfo; }, function (err) { if (args.debug) { - console.error('[HP] loopback test err'); - console.error(err.stack); + console.log('[HP] loopback did not complete'); + console.log(err.stack); } return PromiseA.reject(err); @@ -83,7 +83,7 @@ module.exports.create = function (args) { ip.ports = []; if (opts.debug) { - console.log('[HP] no pretest', opts.pretest); + console.log('[HP] pretest = ', opts.pretest); } if (!opts.pretest) { @@ -124,12 +124,18 @@ module.exports.create = function (args) { if (-1 !== args.protocols.indexOf('upnp') || -1 !== args.protocols.indexOf('ssdp') ) { + if (args.debug) { + console.log('[HP] will try upnp'); + } mappers.push(require('./upnp')); } if (-1 !== args.protocols.indexOf('pmp') || -1 !== args.protocols.indexOf('nat-pmp') ) { + if (args.debug) { + console.log('[HP] will try nat-pmp'); + } mappers.push(require('./pmp')); } diff --git a/lib/pmp.js b/lib/pmp.js index c4c76d1..3a0cddd 100644 --- a/lib/pmp.js +++ b/lib/pmp.js @@ -68,9 +68,11 @@ function pmpForwardHelper(gw, portInfo) { // TODO why did I use a setTimeout here? event loop / timing bug? setTimeout(function () { client.externalIp(function (err, info) { - console.error('[HP] Error: setTimeout client.externalIp:'); - console.error(err.stack); - if (err) { return PromiseA.reject(err); } + if (err) { + console.error('[HP] Error: setTimeout client.externalIp:'); + console.error(err.stack); + return PromiseA.reject(err); + } console.log('Current external IP address: %s', info.ip.join('.')); setPortForward(); }); @@ -78,13 +80,17 @@ function pmpForwardHelper(gw, portInfo) { }); } -function pmpForward(port) { +function pmpForward(portInfo) { return getGateway().then(function (gw) { - return pmpForwardHelper(gw, port); + return pmpForwardHelper(gw, portInfo); }); } module.exports = function (args, ips, portInfo) { + if (args.debug) { + console.log('[HP] [pmp] portInfo'); + console.log(portInfo); + } return pmpForward(portInfo); }; diff --git a/lib/request.js b/lib/request.js index a9cef93..8dedbd0 100644 --- a/lib/request.js +++ b/lib/request.js @@ -8,8 +8,10 @@ function requestAsync(opts) { return new PromiseA(function (resolve, reject) { var httpr = (false === opts.secure) ? http : https; - console.log('[HP] loopback test opts'); - console.log(opts); + if (opts.debug) { + console.log('[HP] requestAsync opts'); + console.log(opts); + } var req = httpr.request(opts, function (res) { var data = ''; @@ -22,10 +24,13 @@ function requestAsync(opts) { reject(err); }); res.on('data', function (chunk) { + clearTimeout(req.__timtok); + if (opts.debug > 2) { console.log('HP: request chunk:'); console.log(chunk); } + data += chunk.toString('utf8'); }); res.on('end', function () { @@ -38,6 +43,13 @@ function requestAsync(opts) { }); req.on('error', reject); + req.setTimeout(3 * 1000); + req.on('socket', function (socket) { + req.__timtok = setTimeout(function () { + req.abort(); + }, 3 * 1000); + socket.setTimeout(3 * 1000); + }); req.end(); }); } diff --git a/lib/upnp.js b/lib/upnp.js index 84dfb42..b092ac7 100644 --- a/lib/upnp.js +++ b/lib/upnp.js @@ -1,17 +1,27 @@ 'use strict'; -//var PromiseA = require('bluebird').Promise; +var PromiseA = require('bluebird').Promise; var natUpnp = require('holepunch-upnp'); function upnpForward(opts) { - return natUpnp.createClient({ timeout: 3000 }).then(function (client) { + if (opts.debug) { + console.log('[HP] [upnp] opts'); + console.log(opts); + } + + return natUpnp.createClient({ timeout: 3 * 1000 }).then(function (client) { + if (opts.debug) { + console.log('[HP] [upnp] created client'); + console.log(client); + } + return client.portMapping({ public: opts.external || opts.public || opts.internal , private: opts.internal || opts.private || opts.public || opts.external , ttl: opts.ttl || 0 }).then(function (result) { if (opts.debug) { - console.log('[HP] upnp result'); + console.log('[HP] [upnp] result'); console.log(result); } return result; @@ -37,7 +47,9 @@ module.exports = function (args, ips, portInfo) { return upnpForward({ debug: args.debug , private: portInfo.internal + , internal: portInfo.internal , public: portInfo.external + , external: portInfo.external // , localAddress: ip.localAddress }); }; diff --git a/package.json b/package.json index 9168928..1a4d85f 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "holepunch", - "version": "1.0.0-alpha.1", + "version": "1.0.0-alpha.2", "description": "Get a direct ip connection by any means possible - direct (public ip), upnp (Microsoft), nat-pmp (Apple), or punch a hole through a firewall using a Reverse VPN (Daplie).", "main": "index.js", "bin": { - "holepunch": "holepunch.js" + "holepunch": "bin/holepunch.js" }, "directories": { "example": "examples" @@ -16,10 +16,11 @@ "holepunch-nat-pmp": "^1.0.0-alpha.1", "holepunch-upnp": "^1.0.0-alpha.1", "localhost.daplie.com-certificates": "^1.1.2", - "netroute": "^1.0.2", - "request": "^2.67.0", "scmp": "^1.0.0" }, + "optionalDependencies": { + "netroute": "^1.0.2" + }, "devDependencies": {}, "scripts": { "test": "echo \"Error: no test specified\" && exit 1"