2014-06-13 64 views
1

我想創建一個使用Node.js的隧道,這將允許我從服務器Y訪問服務器X.服務器X連接到未端口轉發的路由器,在連接之前不知道服務器X的IP,這意味着服務器X必須向服務器Y打開一個套接字,而不是相反。支持任何端口的服務器之間的隧道

我已經使用socket.io成功創建了此版本。服務器X打開服務器Y的套接字,然後用戶可以在Web瀏覽器中訪問服務器Y,服務器Y代理服務器X下的請求。

我想要做的是允許訪問任何類型的端口在服務器X上,不僅轉發網絡請求,而且轉發任何類型的請求。例如,我想允許轉發SSH,以便可以通過服務器Y訪問服務器X上的SSH(不必是端口22)。 localtunnel.me是一個現有的服務,它是我想要實現的一個確切示例。

是否有任何庫可以幫助我實現這個目標,還是我可以很容易地從頭開始構建它?我很容易構建Web請求隧道,也許它可以適應不僅支持Web流量?我已將代碼附加到下面的現有網絡隧道中。

服務器X(連接到服務器Y於端口3001,接收請求用於數據並將其發送回:

var socket = require('socket.io-client')('http://localhost:3001'); 
     socket.on('connect', function(){ 
      console.log('Connected'); 

      // Register the event for request of data 
      socket.on('request', function(data){ 
       // Get the path 
       var options = { 
        host: 'localhost', 
        port: 3000, 
        path: data.path, 
        method: data.method 
       }; 

       var request = http.get(options, function(resp){ 
        resp.on('data', function(chunk){ 
        socket.emit('response', { html: chunk }); 
        // Probably need to fix this for file transfers. Use resp.on('end' 
        }); 
       }).on("error", function(e){ 
        console.log("Got error: " + e.message); 
       }); 

       //Write our post data to the request 
       request.write(data.data); 
       //End the request. 
       request.end(); 

      }); 
      socket.on('disconnect', function(){}); 
     }); 

服務器Y(偵聽端口3001連接到服務器X,並監聽在Web瀏覽器與用戶請求的端口3002轉發到服務器X:

app.listen(3001); 

var rwPortalSocket; 

function handler (req, res) { 
    fs.readFile(__dirname + '/index.html', 
    function (err, data) { 
    if (err) { 
     res.writeHead(500); 
     return res.end('Error loading index.html'); 
    } 

    res.writeHead(200); 
    res.end(data); 
    }); 
} 

io.on('connection', function (socket) { 
    socket.emit('news', { hello: 'world' }); 
    socket.on('my other event', function (data) { 
    console.log(data); 
    }); 
    // Save the socket object 
    rwPortalSocket = socket; 
}); 

console.log('Data channel server running at http://127.0.0.1:3001/'); 

// Create web server 
var http = require('http'); 
var qs = require('querystring'); 

http.createServer(function (req, res) { 
    // Send a request 
    rwPortalSocket.emit('request', { path: req.url, method: req.method }); 

    // When we get a response 
    rwPortalSocket.on('response', function (responseData) { 
     res.writeHead(200); 
     res.end(responseData.html); 
    }); 

}).listen(3002, '127.0.0.1'); 

console.log('Web server running at http://127.0.0.1:3002/'); 

編輯

我現在更新了我的代碼,以便支持任何TCP端口或數據包類型。該代碼工作正常,當我告訴net.connect連接到Web服務器,但是當我告訴它連接SSH服務器,我的SSH客戶端與Protocol error: expected packet type 31, got 20

抱怨我已經添加連接到SSH我的新代碼的例子服務器下面。

服務器X(連接到服務器Y於端口3001,接收請求用於數據並將其發送回:

var socket = require('socket.io-client')('http://localhost:3001'); 
     socket.on('connect', function(){ 
      console.log('Connected'); 

      // Connect to 22 
      var buff = ""; 
      var connected = false; 
      var net = require('net'); 
      var client = net.connect({host: 'myserver.com', port: 22}, function() { //'connect' listener 
       connected = true; 
       console.log('Connected to 22'); 
      }); 

      // Register the event for request of data 
      socket.on('request', function(data){ 

       if (!connected) 
       { 
        client = net.connect({host: 'myserver.com', port: 22}, function() { //'connect' listener 
         connected = true; 
         console.log('Connected to 22'); 
         client.write(data.data); 
        }); 
       } 
       else 
       { 
        client.write(data.data); 
       } 

       client.setMaxListeners(0); 
       // When data comes back to this service, we send it on to the other server 
       client.on('data', function(data) { 
        //console.log(data.toString()); 
        console.log('Server sent back: ' + data.toString()); 
        if (connected) 
        { 
         socket.emit('response', { data: data }); 
        } else { 
         buff += d.toString(); 
        } 
       }); 
       client.on('end', function() { 
        console.log('Disconnected from 22'); 
        connected = false; 
       }); 

       client.on('error', function(e) { 
        console.log(e); 
       }); 

       console.log('Client sent: ' + data.data); 
      }); 
      socket.on('disconnect', function(){}); 
     }); 

服務器Y(偵聽端口3001連接到服務器X,並監聽在SSH客戶端(終端)的用戶請求的端口3002轉發到服務器X:

app.listen(3001); 

var rwPortalSocket; 

function handler (req, res) { 
    fs.readFile(__dirname + '/index.html', 
    function (err, data) { 
    if (err) { 
     res.writeHead(500); 
     return res.end('Error loading index.html'); 
    } 

    res.writeHead(200); 
    res.end(data); 
    }); 
} 

io.on('connection', function (socket) { 
    socket.emit('news', { hello: 'world' }); 
    socket.on('my other event', function (data) { 
    console.log(data); 
    }); 
    // Save the socket object 
    rwPortalSocket = socket; 
}); 

console.log('Data channel server running at http://127.0.0.1:3001/'); 

// Listen for tunnel requests 
net = require('net'); 

var server = net.createServer(function(s) { //'connection' listener 
    s.on('end', function() { 
     console.log('server disconnected'); 
    }); 

    s.on('data', function (d) { 
    rwPortalSocket.emit('request', { data: d }); 
    }); 

    s.on('error', function(e) { 
     console.log(e); 
    }); 

    s.setMaxListeners(0); 

    // When we get a response 
    rwPortalSocket.on('response', function (d) { 
     s.write(d.data); 
    }); 

}); 

server.listen(3002, function() { //'listening' listener 
    console.log('server bound'); 
}); 

console.log('Web server running at http://127.0.0.1:3002/'); 

回答