mostly works
This commit is contained in:
parent
4bc1adf7a2
commit
8e5accc6ce
|
@ -8,6 +8,10 @@ to make home and office devices and services Internet-accessible.
|
|||
|
||||
in development
|
||||
|
||||
```bash
|
||||
node bin/holepunch.js --debug
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
MPL-2.0
|
||||
|
|
|
@ -8,7 +8,8 @@ var cli = require('cli');
|
|||
// TODO txt records for browser plugin: TXT _http.example.com _https.example.com
|
||||
cli.parse({
|
||||
debug: [ false, " show traces and logs", 'boolean', false ]
|
||||
, 'plain-ports': [ false, " Port numbers to test with plaintext loopback. (default: 65080) (formats: <port>,<internal:external>,<internal:external1|external2>)", 'string' ]
|
||||
, 'plain-ports': [ false, " Port numbers to test with plaintext loopback. (default: 65080) (formats: <port>,<internal:external>)", 'string' ]
|
||||
//, 'plain-ports': [ false, " Port numbers to test with plaintext loopback. (default: 65080) (formats: <port>,<internal:external>,<internal:external1|external2>)", 'string' ]
|
||||
, 'tls-ports': [ false, " Port numbers to test with tls loopback. (default: null)", 'string' ]
|
||||
, 'ipify-urls': [ false, " Comma separated list of URLs to test for external ip. (default: api.ipify.org)", 'string' ]
|
||||
, 'protocols': [ false, " Comma separated list of ip mapping protocols. (default: none,upnp,pmp)", 'string' ]
|
||||
|
@ -28,7 +29,7 @@ cli.main(function(_, options) {
|
|||
internal: parseInt(parts[0], 10)
|
||||
, external: (parts[1]||parts[0]).split('|').map(function (port) {
|
||||
return parseInt(port, 10);
|
||||
})
|
||||
})[0]
|
||||
};
|
||||
|
||||
return opts;
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var PromiseA = require('bluebird').Promise;
|
||||
var natpmp = require('nat-pmp');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
exports.pmpForward = function (port) {
|
||||
return new PromiseA(function (resolve, reject) {
|
||||
exec('ip route show default', function (err, stdout, stderr) {
|
||||
var gw;
|
||||
|
||||
if (err || stderr) { reject(err || stderr); return; }
|
||||
|
||||
// default via 192.168.1.1 dev eth0
|
||||
gw = stdout.replace(/^default via (\d+\.\d+\.\d+\.\d+) dev[\s\S]+/m, '$1');
|
||||
console.log('Possible PMP gateway is', gw);
|
||||
|
||||
// create a "client" instance connecting to your local gateway
|
||||
var client = natpmp.connect(gw);
|
||||
|
||||
function setPortForward() {
|
||||
// setup a new port mapping
|
||||
client.portMapping({
|
||||
private: port.private || port.public
|
||||
, public: port.public || port.private
|
||||
, ttl: port.ttl || 0 // 600
|
||||
}, function (err, info) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(info);
|
||||
// {
|
||||
// type: 'tcp',
|
||||
// epoch: 8922109,
|
||||
// private: 22,
|
||||
// public: 2222,
|
||||
// ...
|
||||
// }
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
// explicitly ask for the current external IP address
|
||||
setTimeout(function () {
|
||||
client.externalIp(function (err, info) {
|
||||
if (err) throw err;
|
||||
console.log('Current external IP address: %s', info.ip.join('.'));
|
||||
setPortForward();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function usage() {
|
||||
console.warn("");
|
||||
console.warn("node helpers/pmp-forward [public port] [private port] [ttl]");
|
||||
console.warn("");
|
||||
}
|
||||
|
||||
function run() {
|
||||
var pubPort = parseInt(process.argv[2], 10) || 0;
|
||||
var privPort = parseInt(process.argv[3], 10) || pubPort;
|
||||
var ttl = parseInt(process.argv[4], 10) || 0;
|
||||
var options = { public: pubPort, private: privPort, ttl: ttl };
|
||||
|
||||
if (!pubPort) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
exports.pmpForward(options).then(function () {
|
||||
console.log('done');
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run();
|
||||
}
|
23
lib/index.js
23
lib/index.js
|
@ -43,6 +43,10 @@ module.exports.create = function (args) {
|
|||
Host: args.loopbackHostname
|
||||
}
|
||||
}).then(function (val) {
|
||||
if (args.debug) {
|
||||
console.log('[HP] loopback test reached', val);
|
||||
}
|
||||
|
||||
if (val !== args.value) {
|
||||
return PromiseA.reject(new Error("invalid loopback token value"));
|
||||
}
|
||||
|
@ -53,6 +57,13 @@ module.exports.create = function (args) {
|
|||
portInfo.ips.push(ip);
|
||||
|
||||
return portInfo;
|
||||
}, function (err) {
|
||||
if (args.debug) {
|
||||
console.error('[HP] loopback test err');
|
||||
console.error(err.stack);
|
||||
}
|
||||
|
||||
return PromiseA.reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -67,8 +78,11 @@ module.exports.create = function (args) {
|
|||
return PromiseA.any(opts.ips.map(function (ip) {
|
||||
ip.ports = [];
|
||||
|
||||
if (opts.debug) {
|
||||
console.log('[HP] no pretest', opts.pretest);
|
||||
}
|
||||
|
||||
if (!opts.pretest) {
|
||||
//console.log('[HP pretest]', opts.pretest);
|
||||
return ip;
|
||||
}
|
||||
|
||||
|
@ -116,8 +130,8 @@ module.exports.create = function (args) {
|
|||
return PromiseA.any(mappers.map(function (fn) {
|
||||
var p = fn(args, ips, portInfo);
|
||||
|
||||
if (portInfos.ips.length) {
|
||||
return portInfos;
|
||||
if (portInfo.ips.length) {
|
||||
return portInfo;
|
||||
}
|
||||
|
||||
return p;
|
||||
|
@ -132,8 +146,9 @@ module.exports.create = function (args) {
|
|||
});
|
||||
}).then(function () {
|
||||
return portInfos;
|
||||
}, function () {
|
||||
}, function (err) {
|
||||
console.warn('[HP] RVPN not implemented');
|
||||
console.warn(err.stack);
|
||||
return portInfos;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
'use strict';
|
||||
|
||||
var PromiseA = require('bluebird');
|
||||
var natpmp = require('holepunch-nat-pmp');
|
||||
|
||||
function getGateway() {
|
||||
var exec = require('child_process').exec;
|
||||
var netroute;
|
||||
var gw;
|
||||
|
||||
try {
|
||||
netroute = require('netroute');
|
||||
gw = netroute.getGateway();
|
||||
} catch(e) {
|
||||
}
|
||||
|
||||
if (gw) {
|
||||
return PromiseA.resolve(gw);
|
||||
}
|
||||
|
||||
return new PromiseA(function (resolve, reject) {
|
||||
exec('ip route show default', function (err, stdout, stderr) {
|
||||
var gw;
|
||||
|
||||
if (err || stderr) { reject(err || stderr); return; }
|
||||
|
||||
// default via 192.168.1.1 dev eth0
|
||||
gw = stdout.replace(/^default via (\d+\.\d+\.\d+\.\d+) dev[\s\S]+/m, '$1');
|
||||
console.log('Possible PMP gateway is', gw);
|
||||
|
||||
return gw;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function pmpForwardHelper(gw, portInfo) {
|
||||
return new PromiseA(function (resolve, reject) {
|
||||
// create a "client" instance connecting to your local gateway
|
||||
var client = natpmp.connect(gw);
|
||||
|
||||
function setPortForward() {
|
||||
// setup a new port mapping
|
||||
client.portMapping({
|
||||
private: portInfo.internal || portInfo.private
|
||||
|| portInfo.external || portInfo.public
|
||||
, public: portInfo.external || portInfo.public
|
||||
|| portInfo.internal || portInfo.private
|
||||
, ttl: portInfo.ttl || 0 // 600
|
||||
}, function (err, info) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(info);
|
||||
// {
|
||||
// type: 'tcp',
|
||||
// epoch: 8922109,
|
||||
// private: 22,
|
||||
// public: 2222,
|
||||
// ...
|
||||
// }
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
// explicitly ask for the current external IP address
|
||||
setTimeout(function () {
|
||||
client.externalIp(function (err, info) {
|
||||
if (err) { throw err; }
|
||||
console.log('Current external IP address: %s', info.ip.join('.'));
|
||||
setPortForward();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function pmpForward(port) {
|
||||
return getGateway().then(function (gw) {
|
||||
return pmpForwardHelper(gw, port);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (args, ips, portInfo) {
|
||||
return pmpForward(portInfo);
|
||||
};
|
||||
|
||||
module.exports.pmpForward = pmpForward;
|
||||
|
||||
function usage() {
|
||||
console.warn("");
|
||||
console.warn("node helpers/pmp-forward [public port] [private port] [ttl]");
|
||||
console.warn("");
|
||||
}
|
||||
|
||||
function run() {
|
||||
var pubPort = parseInt(process.argv[2], 10) || 0;
|
||||
var privPort = parseInt(process.argv[3], 10) || pubPort;
|
||||
var ttl = parseInt(process.argv[4], 10) || 0;
|
||||
var options = { public: pubPort, private: privPort, ttl: ttl };
|
||||
|
||||
if (!pubPort) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
exports.pmpForward(options).then(function () {
|
||||
console.log('done');
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run();
|
||||
}
|
|
@ -8,6 +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(typeof opts.port, opts.port);
|
||||
console.log(opts);
|
||||
|
||||
var req = httpr.request(opts, function (res) {
|
||||
var data = '';
|
||||
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
'use strict';
|
||||
|
||||
var PromiseA = require('bluebird').Promise;
|
||||
var natUpnp = require('nat-upnp');
|
||||
//var PromiseA = require('bluebird').Promise;
|
||||
var natUpnp = require('holepunch-upnp');
|
||||
|
||||
exports.upnpForward = function (port) {
|
||||
return natUpnp.createClient({ timeout: 1800 }).then(function (client) {
|
||||
function upnpForward(opts) {
|
||||
return natUpnp.createClient({ timeout: 3000 }).then(function (client) {
|
||||
return client.portMapping({
|
||||
public: port.public,
|
||||
private: port.private || port.public,
|
||||
ttl: port.ttl || 0
|
||||
})/*.then(function () {
|
||||
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(result);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
/*.then(function () {
|
||||
var promitter = client.getMappings();
|
||||
|
||||
promitter.on('entry', function (entry, i) {
|
||||
|
@ -21,10 +28,22 @@ exports.upnpForward = function (port) {
|
|||
});
|
||||
|
||||
return promitter;
|
||||
})*/;
|
||||
});*/
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = function (args, ips, portInfo) {
|
||||
// TODO ips.forEach
|
||||
return upnpForward({
|
||||
debug: args.debug
|
||||
, private: portInfo.internal
|
||||
, public: portInfo.external
|
||||
// , localAddress: ip.localAddress
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.upnpForward = upnpForward;
|
||||
|
||||
/*
|
||||
client.portUnmapping({
|
||||
public: 80
|
Loading…
Reference in New Issue