I'm using nodejs net library.
Locally everything works fine, I can connect to server with client, send data to server and I'm getting response.
But once deployed on server (with traefik), when I run client-app.js I keep getting:
Connected
Received: HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close
400 Bad Request
Connection closed
Traefik is configured to redirect every request that comes to "my-address.com" to 1337 port on docker container (in which runs server-app.js).
Here's my code:
server-app.js:
const net = require('net');
const PORT = 1337;
const HOST = '0.0.0.0';
var server = net.createServer(function(socket) {
socket.write('Echo server\r\n');
//socket.pipe(socket);
socket.on('data', (data) => {
console.log('DATA RECEIVED')
socket.write('GOT DATA', data)
});
});
server.on('connection', (socket)=> {
console.log('Connection from: ', socket.remoteAddress)
});
server.listen(PORT, HOST, () => {
console.log(`SERVER IS UP. PORT ${PORT}`)
})
client-app.js:
const net = require('net');
const PORT = 443;
const HOST = 'my-addres.com';
var client = new net.Socket();
console.dir(client.connect)
client.connect({port: PORT, host: HOST}, function() {
console.log('Connected');
client.write('Hello, server! Love, Client.\n');
var counter = 1;
setInterval(()=>{client.write(`Data nr ${counter}\n`); counter += 1}, 1000)
});
client.on('data', function(data) {
console.log('Received: ' + data);
//client.destroy(); // kill client after server's response
});
client.on('close', function() {
console.log('Connection closed');
});
Your client and server don't speak the HTTP protocol but do their own application protocol on top of TCP. But it looks like you've configured Traefik to be a HTTP router since what you receive is a HTTP response. Since you don't use HTTP you should not use a HTTP but a TCP router instead.
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');
});
The doubt with with code is two things:
When i send request through a browser, i dont get a console log message as "connected" but if i use http.get() or http.request() , it works fine
2)The "connect" event receives a callback with req,clientSocke,head ! now where can i see the server socket ?
const http=require("http")
const server=http.createServer()
server.on("connect",(req,c_socket,head)=>{
console.log("connected")
})
server.listen(5000,()=>{console.log("server up)})
when you access the server via browser, the method is using GET not CONNECT. That's why console.log does not show.
if you want console.log to show when accessing from the browser, you can use request event.
this is an explanation from node.js docs.
'connect' event is emitted each time a server responds to a request
with a CONNECT method. If this event is not being listened for,
clients receiving a CONNECT method will have their connections closed.
node.js docs
you can make a socket server with a net package with createSever method.
this is an example of how to make a simple request to the socket server.
const http = require('http');
const net = require('net');
const { URL } = require('url');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('hello world');
});
server.on('connect', (req, clientSocket, head) => {
console.log('connected');
// Connect to an origin server
const { port, hostname } = new URL(`http://${req.url}`);
const serverSocket = net.connect(port || 80, hostname, () => {
clientSocket.write(
'HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n'
);
serverSocket.write(head);
serverSocket.pipe(clientSocket);
clientSocket.pipe(serverSocket);
});
});
server.listen(5000, () => {
console.log('server up');
});
// Make a request to a tunneling server
const req = http
.request({
port: 5000,
host: 'localhost',
method: 'CONNECT',
path: 'www.google.com:80',
})
.end();
req.on('connect', (res, socket, head) => {
console.log('got connected!');
// Make a request over an HTTP tunnel
socket.write(
'GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n'
);
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
console.log('end');
});
});
I want to know how to create a server in Nodejs to connect clients without the need of a browser. It is difficult to explain, but I mean if it is possible to create a server and also create a client application to connect directly between computers. Attention, I do not want to create an http server.
Maybe next sample that's you are looking for. I think you need use tcp instead http.
/*
TCP (net) Server
*/
var net = require('net');
var server = net.createServer(function(socket) {
socket.write('Echo server\r\n');
socket.pipe(socket);
});
server.listen(1337, '127.0.0.1');
/*
$ netcat 127.0.0.1 1337
You should see:
> Echo server
*/
/* TCP (net) client */
var net = require('net');
var client = new net.Socket();
client.connect(1337, '127.0.0.1', function() {
console.log('Connected');
client.write('Hello, server!');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.end(); // kill client after server's response
});
client.on('close', function() {
console.log('Connection closed');
});
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).
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();
});