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 | in development | ||||||
| 
 | 
 | ||||||
|  | ```bash | ||||||
|  | node bin/holepunch.js --debug | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| # License | # License | ||||||
| 
 | 
 | ||||||
| MPL-2.0 | MPL-2.0 | ||||||
|  | |||||||
| @ -8,7 +8,8 @@ var cli = require('cli'); | |||||||
| // TODO txt records for browser plugin: TXT _http.example.com _https.example.com
 | // TODO txt records for browser plugin: TXT _http.example.com _https.example.com
 | ||||||
| cli.parse({ | cli.parse({ | ||||||
|   debug: [ false, " show traces and logs", 'boolean', false ] |   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' ] | , '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' ] | , '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' ] | , '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) |       internal: parseInt(parts[0], 10) | ||||||
|     , external: (parts[1]||parts[0]).split('|').map(function (port) { |     , external: (parts[1]||parts[0]).split('|').map(function (port) { | ||||||
|         return parseInt(port, 10); |         return parseInt(port, 10); | ||||||
|       }) |       })[0] | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     return opts; |     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 |         Host: args.loopbackHostname | ||||||
|       } |       } | ||||||
|     }).then(function (val) { |     }).then(function (val) { | ||||||
|  |       if (args.debug) { | ||||||
|  |         console.log('[HP] loopback test reached', val); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       if (val !== args.value) { |       if (val !== args.value) { | ||||||
|         return PromiseA.reject(new Error("invalid loopback token value")); |         return PromiseA.reject(new Error("invalid loopback token value")); | ||||||
|       } |       } | ||||||
| @ -53,6 +57,13 @@ module.exports.create = function (args) { | |||||||
|       portInfo.ips.push(ip); |       portInfo.ips.push(ip); | ||||||
| 
 | 
 | ||||||
|       return portInfo; |       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) { |     return PromiseA.any(opts.ips.map(function (ip) { | ||||||
|       ip.ports = []; |       ip.ports = []; | ||||||
| 
 | 
 | ||||||
|  |       if (opts.debug) { | ||||||
|  |         console.log('[HP] no pretest', opts.pretest); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|       if (!opts.pretest) { |       if (!opts.pretest) { | ||||||
|         //console.log('[HP pretest]', opts.pretest);
 |  | ||||||
|         return ip; |         return ip; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| @ -116,8 +130,8 @@ module.exports.create = function (args) { | |||||||
|         return PromiseA.any(mappers.map(function (fn) { |         return PromiseA.any(mappers.map(function (fn) { | ||||||
|           var p = fn(args, ips, portInfo); |           var p = fn(args, ips, portInfo); | ||||||
| 
 | 
 | ||||||
|           if (portInfos.ips.length) { |           if (portInfo.ips.length) { | ||||||
|             return portInfos; |             return portInfo; | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           return p; |           return p; | ||||||
| @ -132,8 +146,9 @@ module.exports.create = function (args) { | |||||||
|       }); |       }); | ||||||
|     }).then(function () { |     }).then(function () { | ||||||
|       return portInfos; |       return portInfos; | ||||||
|     }, function () { |     }, function (err) { | ||||||
|       console.warn('[HP] RVPN not implemented'); |       console.warn('[HP] RVPN not implemented'); | ||||||
|  |       console.warn(err.stack); | ||||||
|       return portInfos; |       return portInfos; | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  | |||||||
							
								
								
									
										114
									
								
								lib/pmp.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								lib/pmp.js
									
									
									
									
									
										Normal file
									
								
							| @ -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) { |   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'); | ||||||
|  |     console.log(typeof opts.port, opts.port); | ||||||
|  |     console.log(opts); | ||||||
|  | 
 | ||||||
|     var req = httpr.request(opts, function (res) { |     var req = httpr.request(opts, function (res) { | ||||||
|       var data = ''; |       var data = ''; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,15 +1,22 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var PromiseA = require('bluebird').Promise; | //var PromiseA = require('bluebird').Promise;
 | ||||||
| var natUpnp = require('nat-upnp'); | var natUpnp = require('holepunch-upnp'); | ||||||
| 
 | 
 | ||||||
| exports.upnpForward = function (port) { | function upnpForward(opts) { | ||||||
|   return natUpnp.createClient({ timeout: 1800 }).then(function (client) { |   return natUpnp.createClient({ timeout: 3000 }).then(function (client) { | ||||||
|     return client.portMapping({ |     return client.portMapping({ | ||||||
|       public: port.public, |       public: opts.external || opts.public || opts.internal | ||||||
|       private: port.private || port.public, |     , private: opts.internal || opts.private || opts.public || opts.external | ||||||
|       ttl: port.ttl || 0 |     , ttl: opts.ttl || 0 | ||||||
|     })/*.then(function () { |     }).then(function (result) { | ||||||
|  |       if (opts.debug) { | ||||||
|  |         console.log('[HP] upnp result'); | ||||||
|  |         console.log(result); | ||||||
|  |       } | ||||||
|  |       return result; | ||||||
|  |     }); | ||||||
|  |     /*.then(function () { | ||||||
|       var promitter = client.getMappings(); |       var promitter = client.getMappings(); | ||||||
| 
 | 
 | ||||||
|       promitter.on('entry', function (entry, i) { |       promitter.on('entry', function (entry, i) { | ||||||
| @ -21,10 +28,22 @@ exports.upnpForward = function (port) { | |||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       return promitter; |       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({ | client.portUnmapping({ | ||||||
|   public: 80 |   public: 80 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user