I'm trying to create a tunnel using Node.js that will allow me to access Server X from Server Y. Server X is connected to a router that isn't port forwarded and I won't know the IP of Server X until it connects, which means that Server X has to open a socket to Server Y and not the other way round.
I've successfully created a version of this using socket.io. Server X opens a socket to server Y, the user can then access Server Y in a web browser and Server Y proxies the requests down the socket to Server X.
What I would like to do is allow access to any kind of port on Server X, and forward not just web requests but requests of any kind. For example, I'd like to allow forwarding of SSH so I can access SSH on Server X through Server Y (doesn't have to be port 22). localtunnel.me is an existing service which is an exact example of what I want to achieve.
Are there any libraries that could help me achieve this, or can I build it from the ground up quite easily? I built the web request tunnel easily, perhaps it can be adapted to support not just web traffic? I've attached the code to my existing web tunnel below.
Server X (connects to Server Y on port 3001, receives requests for data and sends it back:
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(){});
});
Server Y (listens on port 3001 to connect to Server X, and listens on port 3002 for requests from user in web browser to forward to Server 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/');
EDIT
I've now updated my code so that should support any TCP port or packet type. The code works fine when I tell net.connect to connect to a web server, but when I tell it to connect an SSH server, my SSH client complains with Protocol error: expected packet type 31, got 20
I've added an example of my new code connecting to an SSH server below.
Server X (connects to Server Y on port 3001, receives requests for data and sends it back:
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(){});
});
Server Y (listens on port 3001 to connect to Server X, and listens on port 3002 for requests from user in SSH Client (terminal) to forward to Server 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/');
If the "connections" to Server X would all be TCP-based, you could have an SSH server running on both ends. Server X would then connect to Server Y to only forward some port on Server Y that would point to the SSH server running on Server X. Then you could use a node module like ssh2 to connect to any port on Server X.
Another option for dynamic forwarding would be to set up a socks proxy as described in this answer. From there you could use a socks client module from npm, such as socks5-client.
If instead you have a fixed set of ports that you want have available, you could simplify the above solutions by just having an SSH server on Server Y and Server X connects and creates a port forward for each port you want to have available.
Here is an example of another option: connecting to Server X from Server Y via SSH and opening up connections on Server X using the SSH connection (via ssh2).
Related
My plan is to create a proxy of my phone 4g connection.
I've made a direct tcp connection of my phone to my pc via nodejs.
I create a client.js on my phone and server.js on my pc. They connect.
Now i need to 'transform' this direct connection into a proxy, but i dont know how.
Any help i would aprecciate.
I will show my server.js and client.js code below.
Server.js
var net = require('net');
var tcpServerPort = 7000;
// a simple TCP server for testing
var server = net.createServer(function (socket) {
console.log('Client connected to server');
socket.on('close', function () {
console.log('Client disconnected from server');
});
socket.on('data', function (buffer) {
// 'echo' server
socket.write(buffer);
});
socket.on('error', function (err) {
console.log('Error: ' + err.soString());
});
});
server.listen(tcpServerPort);
Client.js
const net = require('net');
const client = new net.Socket();
const port = 7000;
const host = 'my home ip';
client.connect(port, host, function() {
console.log('Connected');
client.write("Hello From Client " + client.address().address);
});
client.on('data', function(data) {
console.log('Server Says : ' + data);
});
client.on('close', function() {
console.log('Connection closed');
});
I created a simple tcp server using code
var net = require('net');
// Setup a tcp server
var server = net.createServer(function (socket) {
socket.addListener("connect", function () {
console.log('hello');
sys.puts("Connection from " + socket.remoteAddress);
socket.end("Hello World\n");
});
});
server.listen(7000, "127.0.0.1");
console.log("TCP server listening on port 7000 at 127.0.0.1");
It started successfully, but how can I send some test msg to that tcp server, I tried SocketTest v.3 but not console output.
Use data event handler to receive data in the server.
socket.on('data', function(data) {
console.log(data);
// echo back
socket.write('You said '+data);
});
For people still looking for answers, here's how I did it with SocketTest
const net = require('net');
const client = new net.Socket();
const HOST = "127.0.0.1";
const PORT = 7000;
client.on('data', () => {
client.destroy(); // kill after response
});
client.on('error', () => {
client.destroy(); // kill
});
client.connect(PORT, HOST, () => {
client.write('Hello world!');
client.end();
});
I'm trying to punch a TCP hole through two NATs in node.js. The problem is I can't figure out how to choose which local port the connection should use?
After creating a connection with the public server, you also need to listen on the exact same local (!!) port that was used to establish that connection.
I extended your testcode to a complete tcp hole punching proof of concept:
// server.js
var server = require('net').createServer(function (socket) {
console.log('> Connect to this public endpoint with clientB:', socket.remoteAddress + ':' + socket.remotePort);
}).listen(4434, function (err) {
if(err) return console.log(err);
console.log('> (server) listening on:', server.address().address + ':' + server.address().port)
});
// clientA.js
var c = require('net').createConnection({host : 'PUBLIC_IP_OF_SERVER', port : 4434}, function () {
console.log('> connected to public server via local endpoint:', c.localAddress + ':' + c.localPort);
// do not end the connection, keep it open to the public server
// and start a tcp server listening on the ip/port used to connected to server.js
var server = require('net').createServer(function (socket) {
console.log('> (clientA) someone connected, it\s:', socket.remoteAddress, socket.remotePort);
socket.write("Hello there NAT traversal man, this is a message from a client behind a NAT!");
}).listen(c.localPort, c.localAddress, function (err) {
if(err) return console.log(err);
console.log('> (clientA) listening on:', c.localAddress + ':' + c.localPort);
});
});
// clientB.js
// read the server's output to find the public endpoint of A:
var c = require('net').createConnection({host : 'PUBLIC_IP_OF_CLIENT_A', port : PUBLIC_PORT_OF_CLIENT_A},function () {
console.log('> (clientB) connected to clientA!');
c.on('data', function (data) {
console.log(data.toString());
});
});
For a more complete version with signalling happening on the server, I refer to my code here: https://github.com/SamDecrock/node-tcp-hole-punching
The socket is assigned a local port. To reuse the same port you can connect to the client using the same socket that was used to communicate with the server. This works for you because you are doing TCP hole punching. However, you cannot choose a port yourself.
Here is some test code:
// server.js
require('net').createServer(function(c) {
c.write(c.remotePort.toString(10));
}).listen(4434);
//client.js
var c = require('net').createConnection({host : '127.0.0.1', port : 4434});
c.on('data', function(data) {
console.log(data.toString(), c.localPort);
c.end();
});
c.on('end', function() {
c.connect({host : '127.0.0.1', port : 4434});
});
Is it possible to connect to a NodeJS Server from another server? Two NodeJS servers communicating with each other?
//Server Code
var io = require('socket.io').listen(8090);
io.sockets.on('connection', function (socket) {
io.sockets.emit('this', { will: 'be received by everyone'});
socket.on('private message', function (from, msg) {
console.log('I received a private message by ', from, ' saying ', msg);
});
socket.on('disconnect', function () {
io.sockets.emit('user disconnected');
});
});
//Client Code in Server Code. Connecting to another server.
io.connect( "http://192.168.0.104:8091" ); //Connect to another server from this one.
//ETC...
Here's a simple example that creates a server and a client that connects to that server. Remember that what you send has to be a buffer (strings are automatically converted to buffers). The client and server works independently of eachother, so can be put in the same app or on totally different computers.
Server (server.js):
const net = require("net");
// Create a simple server
var server = net.createServer(function (conn) {
console.log("Server: Client connected");
// If connection is closed
conn.on("end", function() {
console.log('Server: Client disconnected');
// Close the server
server.close();
// End the process
process.exit(0);
});
// Handle data from client
conn.on("data", function(data) {
data = JSON.parse(data);
console.log("Response from client: %s", data.response);
});
// Let's response with a hello message
conn.write(
JSON.stringify(
{ response: "Hey there client!" }
)
);
});
// Listen for connections
server.listen(61337, "localhost", function () {
console.log("Server: Listening");
});
Client (client.js):
const net = require("net");
// Create a socket (client) that connects to the server
var socket = new net.Socket();
socket.connect(61337, "localhost", function () {
console.log("Client: Connected to server");
});
// Let's handle the data we get from the server
socket.on("data", function (data) {
data = JSON.parse(data);
console.log("Response from server: %s", data.response);
// Respond back
socket.write(JSON.stringify({ response: "Hey there server!" }));
// Close the connection
socket.end();
});
The conn and socket objects both implement the Stream interface.
Check Substrack's dnode. It auto maps literal objects from the 1st env to the 2nd one. You gain a kind of RPC out of the box. And it works in the browser too...
I have created a TCP server using Node.js which listens to clients connections.
I need to transmit data from TCP server to HTTP server again in Node.js possibly through a Websocket (socket.io).
However, I do not know how to create such connection such that TCP server is able to push data to HTTP server through Websocket.
Many Thanks.
I was trying lot of things to get this work. Most of the time I was relying on socket.io to get this working, but it was just not working with TCP.
However, net.Socket suffices the purpose.
Here is the working example of it.
TCP Server
var net = require('net');
var HOST = 'localhost';
var PORT = 4040;
var server = net.createServer();
server.listen(PORT, HOST);
server.on('connection', function(sock) {
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
sock.write("TCP sending message : 1");
console.log('Server listening on ' + server.address().address +':'+
server.address().port);
}).listen(PORT, HOST);
HTTP Server
var http = require('http').createServer(httpHandler),
fs = require("fs"),
wsock = require('socket.io').listen(http),
tcpsock = require('net');
var http_port = 8888;
var tcp_HOST = 'localhost';
var tcp_PORT = 4040;
/**
* http server
*/
function httpHandler (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);
});
}
http.listen(http_port);
console.info("HTTP server listening on " + http_port);
wsock.sockets.on('connection', function (socket) {
var tcpClient = new tcpsock.Socket();
tcpClient.setEncoding("ascii");
tcpClient.setKeepAlive(true);
tcpClient.connect(tcp_PORT, tcp_HOST, function() {
console.info('CONNECTED TO : ' + tcp_HOST + ':' + tcp_PORT);
tcpClient.on('data', function(data) {
console.log('DATA: ' + data);
socket.emit("httpServer", data);
});
tcpClient.on('end', function(data) {
console.log('END DATA : ' + data);
});
});
socket.on('tcp-manager', function(message) {
console.log('"tcp" : ' + message);
return;
});
socket.emit("httpServer", "Initial Data");
});
Browser Client
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
socket.on('httpServer', function (data) {
console.log(data);
document.write(data + "\r\n");
socket.emit('tcp', "For TCP");
});
</script>
This way, there is a socket opened between HTTP server and TCP server in Node.js.
If you need to communicate server-server than websockets is probably not a best choice. Try one of RPC libraries, or just use HTTP or your own protocol.
You can use either socket.io or ws (only WebSocket) on Node.js as client (not only in browser)
var io = require('socket.io-client');
var socket = io.connect('http://IP address of Websocket server');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});