Туннель между серверами, поддерживающий любой порт

Я пытаюсь создать туннель с помощью Node.js, который позволит мне получить доступ к серверу X с сервера Y. Сервер X подключен к маршрутизатору, который не перенаправлен через порт, и я не буду знать IP-адрес сервера X, пока он не будет подключается, что означает, что сервер X должен открыть сокет для сервера Y, а не наоборот.

Я успешно создал версию этого с помощью socket.io, Сервер X открывает сокет для сервера Y, затем пользователь может получить доступ к Серверу Y в веб-браузере, а Сервер Y передает запросы через сокет на Сервер X.

Я хотел бы разрешить доступ к любому порту на сервере X и пересылать не только веб-запросы, но и запросы любого рода. Например, я хотел бы разрешить пересылку SSH, чтобы я мог получить доступ к SSH на сервере X через сервер Y (не обязательно должен быть порт 22). localtunnel.me это существующий сервис, который является точным примером того, чего я хочу достичь.

Существуют ли какие-либо библиотеки, которые могли бы помочь мне достичь этого, или я могу построить это с нуля довольно легко? Я легко построил туннель веб-запросов, возможно, его можно адаптировать для поддержки не только веб-трафика? Я прикрепил код к моему существующему веб-туннелю ниже.

Сервер 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 и прослушивает порт 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 подключиться к веб-серверу, но когда я говорю ему подключить 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 и прослушивает порт 3002 для запросов от пользователя в SSH Client (терминал) для пересылки на Сервер 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/');

1 ответ

Если бы все "подключения" к серверу X были бы основаны на TCP, сервер SSH мог бы работать на обоих концах. Затем сервер X будет подключаться к серверу Y, чтобы переадресовывать только некоторый порт на сервере Y, который будет указывать на SSH-сервер, работающий на сервере X. Затем вы можете использовать модуль узла, такой как ssh2, для подключения к любому порту на сервере X.

Другой вариант динамической пересылки - настроить прокси-сервер socks, как описано в этом ответе. Оттуда вы можете использовать клиентский модуль socks из npm, например, socks5-client.

Если вместо этого у вас есть фиксированный набор портов, которые вы хотите иметь доступными, вы могли бы упростить вышеуказанные решения, просто подключив SSH-сервер к серверу Y, и сервер X подключится и создаст переадресацию портов для каждого порта, который вы хотите иметь доступным.

Вот пример другого варианта: подключение к Серверу X с Сервера Y через SSH и открытие соединений на Сервере X с использованием соединения SSH (через ssh2).

Другие вопросы по тегам