diff --git a/src/app/app.js b/src/app/app.js index 152b501..f2fba1d 100644 --- a/src/app/app.js +++ b/src/app/app.js @@ -105,6 +105,18 @@ class App extends Component { this.forceUpdate() } }) + + window.torrentSocket.emit('p2pStatus', (status) => { + if(status == 0) + return + + window.p2pStatus = status + this.forceUpdate() + }) + window.torrentSocket.on('p2pStatus', (status) => { + window.p2pStatus = status + this.forceUpdate() + }) } componentWillUnmount() { appReady = false; diff --git a/src/app/header.js b/src/app/header.js index dd0efc0..17f35a0 100644 --- a/src/app/header.js +++ b/src/app/header.js @@ -113,10 +113,25 @@ const Header = (props) => { { !window.currentWindow.isModal() && -
0 ? '#42f445' : 'white'}}> - rats peers: {window.peers} {window.peers > 0 ? ' (p2p rats search enabled)' : ' (p2p rats search not available at this moment)'} +
0 ? '#42f445' : 'white'}}> +
rats peers: {window.peers} {window.peers > 0 ? ' (p2p rats search enabled)' : ' (p2p rats search not available at this moment)'}
+ { + window.p2pStatus == 0 + && +
extenal connection not avaible (check port forwarding)
+ } + { + window.p2pStatus == 1 + && +
port not available, but connections redirected
+ } + { + window.p2pStatus == 2 + && +
port connections fully avaible
+ }
- } + }
diff --git a/src/background/p2p.js b/src/background/p2p.js index f3d5aaa..ad1e6aa 100644 --- a/src/background/p2p.js +++ b/src/background/p2p.js @@ -1,13 +1,17 @@ +import ssh from './ssh' const config = require('./config'); const net = require('net') const JsonSocket = require('json-socket') const os = require('os'); +const isPortReachable = require('./isPortReachable') class p2p { peers = [] ignoreAddresses = [] messageHandlers = {} + externalPeers = [] size = 0 + p2pStatus = 0 constructor(send = () => {}) { @@ -99,6 +103,50 @@ class p2p { this.tcpServer.listen(config.spiderPort, '0.0.0.0'); } + checkPortAndRedirect(address, port) { + isPortReachable(port, {host: address}).then((isAvailable) => { + this.p2pStatus = isAvailable ? 2 : 0 + this.send('p2pStatus', this.p2pStatus) + + // all ok don't need to start any ssh tunnels + if(isAvailable) + { + console.log('tcp p2p port is reachable - all ok') + return; + } + else + { + console.log('tcp p2p port is unreachable - try ssh tunnel') + } + + if(!this.encryptor) + { + console.error('something wrong with encryptor') + return + } + + let remoteHost = '03de848286b8fbe6e775e6601c3bcfb9b71dfddcacb861b061458ce5e4020a15a649aabef88234d2af01ead4276a6de1YlqiJBlXCmoA7TpnbRuSRHNDsIBLlZ9McbovKJXHtAA=' + + ssh(config.spiderPort, this.encryptor.decrypt(remoteHost), 'relay', 'relaymytrf', (selfPeer) => { + if(!selfPeer) + { + this.p2pStatus = 0 + this.send('p2pStatus', this.p2pStatus) + this.externalPeers = [] + return + } + + console.log('ssh tunnel success, redirect peers to ssh') + + this.p2pStatus = 1 + this.send('p2pStatus', this.p2pStatus) + this.ignore(selfPeer) + this.emit('peer', selfPeer) + this.externalPeers = [selfPeer] // add external peers and tell this on every connection + }) + }) + } + on(type, callback) { this.messageHandlers[type] = callback } @@ -112,13 +160,24 @@ class p2p { if(address.port <= 1 || address.port > 65535) return; - if(this.ignoreAddresses.includes(address.address)) - return; + // check ignore + for(const ignoreAddress of this.ignoreAddresses) + { + if(typeof ignoreAddress === 'object') + { + if(ignoreAddress.address === address.address && ignoreAddress.port === address.port) + return + } + else + { + if(ignoreAddress === address.address) + return + } + } for(let peer of peers) { - if(peer.address === address.address) { - peer.port = address.port; + if(peer.address === address.address && peer.port === address.port) { return; } } @@ -156,7 +215,7 @@ class p2p { emit('protocol', { protocol: 'rats', port: config.spiderPort, - peers: this.peersList().slice(0, 4).map(peer => ({address: peer.address, port: peer.port})) + peers: this.peersList().slice(0, 4).map(peer => ({address: peer.address, port: peer.port})).concat(this.externalPeers) // also add external peers }, (data) => { if(!data || data.protocol != 'rats') return diff --git a/src/background/spider.js b/src/background/spider.js index 456b9c7..d275ef3 100644 --- a/src/background/spider.js +++ b/src/background/spider.js @@ -259,6 +259,7 @@ setInterval(() => { }, 24 * 60 * 60 * 1000); const p2p = new P2PServer(send) +p2p.encryptor = encryptor p2p.listen() // load initial peers if(dataDirectory && fs.existsSync(dataDirectory + '/peers.p2p')) @@ -724,6 +725,14 @@ if(config.p2pBootstrap) callback(p2p.size) }); + recive('p2pStatus', (callback) => + { + if(typeof callback != 'function') + return; + + callback(p2p.p2pStatus) + }); + recive('config', (callback) => { if(typeof callback != 'function') @@ -1213,6 +1222,9 @@ checkInternet((connected) => { console.log('p2p stun ignore my address', address) p2p.ignore(address) + + // check port avalibility + p2p.checkPortAndRedirect(address, config.spiderPort) }) stunServer.send(stunRequest, 19302, 'stun.l.google.com') }) diff --git a/src/background/ssh.js b/src/background/ssh.js index 3355fdd..943a31b 100644 --- a/src/background/ssh.js +++ b/src/background/ssh.js @@ -19,13 +19,13 @@ const startSSH = (port, host, user, password, callback) => { } const options = [ + '-N', '-T', '-R', `0.0.0.0:${remotePort}:127.0.0.1:${port}`, `${user}@${host}`, '-pw', password, '-v' ] - console.log(options) const ssh = spawn(appPath('plink'), options) @@ -56,15 +56,13 @@ const startSSH = (port, host, user, password, callback) => { if(data.includes('Password authentication failed')) { ssh.kill() - if(callback) - callback(false) } }); ssh.on('close', (code, signal) => { + console.log(`ssh closed with code ${code} and signal ${signal}`) if(callback) callback(false) - console.log(`ssh closed with code ${code} and signal ${signal}`) }) return ssh