tested working upnp and pmp

This commit is contained in:
AJ ONeal 2015-12-30 21:40:52 +00:00
parent 62509a4800
commit 6382701c91
8 changed files with 123 additions and 23 deletions

View File

@ -1,17 +1,79 @@
# holepunch # 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 and ZeroConf (Bonjour) NAT-PMP
to make home and office devices and services Internet-accessible. to make home and office devices and services Internet-accessible.
## Progress ## Progress
in development it now works :-)
still in development
```bash ```bash
git clone git@github.com:Daplie/holepunch.git
pushd holepunch
node bin/holepunch.js --debug 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: <port>,<internal:external>)
--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 # License
MPL-2.0 MPL-2.0

View File

@ -71,7 +71,8 @@ cli.main(function(_, options) {
} }
return hp.create(args).then(function () { return hp.create(args).then(function () {
console.log('wishing wanting waiting'); //console.log('[HP] wishing wanting waiting');
//process.exit(0); console.log('complete, exiting');
process.exit(0);
}); });
}); });

View File

@ -41,7 +41,7 @@ function createSocket() {
}); });
socket.on('message', function (chunk, info) { socket.on('message', function (chunk, info) {
var message = chunk.toString(); var message = chunk.toString('utf8');
console.log('[MESSAGE RECEIVED]'); console.log('[MESSAGE RECEIVED]');
console.log(info); console.log(info);

View File

@ -14,7 +14,7 @@ module.exports.create = function (args) {
if (args.debug) { if (args.debug) {
console.log('[HP] create servers'); console.log('[HP] create servers');
console.log(servers); //console.log(servers);
} }
function getExternalIps() { function getExternalIps() {
@ -63,8 +63,8 @@ module.exports.create = function (args) {
return portInfo; return portInfo;
}, function (err) { }, function (err) {
if (args.debug) { if (args.debug) {
console.error('[HP] loopback test err'); console.log('[HP] loopback did not complete');
console.error(err.stack); console.log(err.stack);
} }
return PromiseA.reject(err); return PromiseA.reject(err);
@ -83,7 +83,7 @@ module.exports.create = function (args) {
ip.ports = []; ip.ports = [];
if (opts.debug) { if (opts.debug) {
console.log('[HP] no pretest', opts.pretest); console.log('[HP] pretest = ', opts.pretest);
} }
if (!opts.pretest) { if (!opts.pretest) {
@ -124,12 +124,18 @@ module.exports.create = function (args) {
if (-1 !== args.protocols.indexOf('upnp') if (-1 !== args.protocols.indexOf('upnp')
|| -1 !== args.protocols.indexOf('ssdp') || -1 !== args.protocols.indexOf('ssdp')
) { ) {
if (args.debug) {
console.log('[HP] will try upnp');
}
mappers.push(require('./upnp')); mappers.push(require('./upnp'));
} }
if (-1 !== args.protocols.indexOf('pmp') if (-1 !== args.protocols.indexOf('pmp')
|| -1 !== args.protocols.indexOf('nat-pmp') || -1 !== args.protocols.indexOf('nat-pmp')
) { ) {
if (args.debug) {
console.log('[HP] will try nat-pmp');
}
mappers.push(require('./pmp')); mappers.push(require('./pmp'));
} }

View File

@ -68,9 +68,11 @@ function pmpForwardHelper(gw, portInfo) {
// TODO why did I use a setTimeout here? event loop / timing bug? // TODO why did I use a setTimeout here? event loop / timing bug?
setTimeout(function () { setTimeout(function () {
client.externalIp(function (err, info) { client.externalIp(function (err, info) {
if (err) {
console.error('[HP] Error: setTimeout client.externalIp:'); console.error('[HP] Error: setTimeout client.externalIp:');
console.error(err.stack); console.error(err.stack);
if (err) { return PromiseA.reject(err); } return PromiseA.reject(err);
}
console.log('Current external IP address: %s', info.ip.join('.')); console.log('Current external IP address: %s', info.ip.join('.'));
setPortForward(); setPortForward();
}); });
@ -78,13 +80,17 @@ function pmpForwardHelper(gw, portInfo) {
}); });
} }
function pmpForward(port) { function pmpForward(portInfo) {
return getGateway().then(function (gw) { return getGateway().then(function (gw) {
return pmpForwardHelper(gw, port); return pmpForwardHelper(gw, portInfo);
}); });
} }
module.exports = function (args, ips, portInfo) { module.exports = function (args, ips, portInfo) {
if (args.debug) {
console.log('[HP] [pmp] portInfo');
console.log(portInfo);
}
return pmpForward(portInfo); return pmpForward(portInfo);
}; };

View File

@ -8,8 +8,10 @@ function requestAsync(opts) {
return new PromiseA(function (resolve, reject) { return new PromiseA(function (resolve, reject) {
var httpr = (false === opts.secure) ? http : https; var httpr = (false === opts.secure) ? http : https;
console.log('[HP] loopback test opts'); if (opts.debug) {
console.log('[HP] requestAsync opts');
console.log(opts); console.log(opts);
}
var req = httpr.request(opts, function (res) { var req = httpr.request(opts, function (res) {
var data = ''; var data = '';
@ -22,10 +24,13 @@ function requestAsync(opts) {
reject(err); reject(err);
}); });
res.on('data', function (chunk) { res.on('data', function (chunk) {
clearTimeout(req.__timtok);
if (opts.debug > 2) { if (opts.debug > 2) {
console.log('HP: request chunk:'); console.log('HP: request chunk:');
console.log(chunk); console.log(chunk);
} }
data += chunk.toString('utf8'); data += chunk.toString('utf8');
}); });
res.on('end', function () { res.on('end', function () {
@ -38,6 +43,13 @@ function requestAsync(opts) {
}); });
req.on('error', reject); 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(); req.end();
}); });
} }

View File

@ -1,17 +1,27 @@
'use strict'; 'use strict';
//var PromiseA = require('bluebird').Promise; var PromiseA = require('bluebird').Promise;
var natUpnp = require('holepunch-upnp'); var natUpnp = require('holepunch-upnp');
function upnpForward(opts) { 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({ return client.portMapping({
public: opts.external || opts.public || opts.internal public: opts.external || opts.public || opts.internal
, private: opts.internal || opts.private || opts.public || opts.external , private: opts.internal || opts.private || opts.public || opts.external
, ttl: opts.ttl || 0 , ttl: opts.ttl || 0
}).then(function (result) { }).then(function (result) {
if (opts.debug) { if (opts.debug) {
console.log('[HP] upnp result'); console.log('[HP] [upnp] result');
console.log(result); console.log(result);
} }
return result; return result;
@ -37,7 +47,9 @@ module.exports = function (args, ips, portInfo) {
return upnpForward({ return upnpForward({
debug: args.debug debug: args.debug
, private: portInfo.internal , private: portInfo.internal
, internal: portInfo.internal
, public: portInfo.external , public: portInfo.external
, external: portInfo.external
// , localAddress: ip.localAddress // , localAddress: ip.localAddress
}); });
}; };

View File

@ -1,10 +1,10 @@
{ {
"name": "holepunch", "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).", "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", "main": "index.js",
"bin": { "bin": {
"holepunch": "holepunch.js" "holepunch": "bin/holepunch.js"
}, },
"directories": { "directories": {
"example": "examples" "example": "examples"
@ -16,10 +16,11 @@
"holepunch-nat-pmp": "^1.0.0-alpha.1", "holepunch-nat-pmp": "^1.0.0-alpha.1",
"holepunch-upnp": "^1.0.0-alpha.1", "holepunch-upnp": "^1.0.0-alpha.1",
"localhost.daplie.com-certificates": "^1.1.2", "localhost.daplie.com-certificates": "^1.1.2",
"netroute": "^1.0.2",
"request": "^2.67.0",
"scmp": "^1.0.0" "scmp": "^1.0.0"
}, },
"optionalDependencies": {
"netroute": "^1.0.2"
},
"devDependencies": {}, "devDependencies": {},
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"