NodeJS TCP Socket does not show client hostname information - node.js

lets say I've created a simple node.js TCP Socket server as follows.
var server = net.createServer(function (socket) {
socket.end("goodbye\n");
});
// listen on port 80, like a webserver would, and configured to accept connections to multiple hosts, ie test.example.com, sdfsdfsdf.example.com, example2.com.
server.listen(80, function() {
address = server.address();
console.log("opened server on %j", address);
});
server.on('connection', function(socket) {
//log('connection data', socket);
log('CONNECTED SOCKET DATA', socket.address());
log('CONNECTED LOCAL, %s:%s', socket.localAddress, socket.localPort);
log('CONNECTED %s:%s', socket.remoteAddress, socket.remotePort);
//How do I find the server hostname that the client connected to?
// eg test.example.com or example2.com
});
Once a tcp connection is made, I want to parse the hostname that the client attempted to connect to. However the socket does not seem to have this information.
The following is what I got when I ran the previous code (removed ip addresses)
CONNECTED SOCKET DATA { port: 80, family: 2, address: '[SERVER IP ADDRESS]' }
CONNECTED LOCAL, undefined:undefined
CONNECTED [CLIENT IP ADDRESS]:13263
I've gone through the nodejs socket documentation but I cant find anything related to host name. The documentation actually says that the socket.localAddress will be an IP Address, with makes it useless in my case.

That information is not available at the TCP layer. You need to look at the Host header at the HTTP layer when a request arrives. This will be available as req.headers.host when a request arrives. http://nodejs.org/docs/latest/api/all.html#all_message_headers
Also based on your comment, trying to run a non-HTTP server on port 80 is asking for trouble. You are going to get connections from web spiders and botnets all the time, so make sure your program properly handles HTTP clients connecting and disconnects them or perhaps sends an HTTP error message.
Joe is correct in the comment that if you are not using HTTP, your custom protocol will need to transmit the "virtual host" name from the client to the server in the first packet/header message of your custom protocol.

Related

Node.js - Bi-directional communication between a tcp server and web portal

I've a GPS tracker device that sends data to my Node.js TCP server and I can send data back to device from the TCP server.
const net = require('net');
const port = 6565;
const host = '127.0.0.1';
const server = net.createServer(onClientConnection);
function onClientConnection(sock){
console.log(`${sock.remoteAddress}:${sock.remotePort} Connected`);
sock.on('data',function(data){
console.log(`${sock.remoteAddress}:${sock.remotePort} Says : ${data} `);
sock.write("Hello World!");
});
//Handle client connection termination.
sock.on('close',function(){
console.log(`${sock.remoteAddress}:${sock.remotePort} Terminated the connection`);
});
//Handle Client connection error.
sock.on('error',function(error){
console.error(`${sock.remoteAddress}:${sock.remotePort} Connection Error ${error}`);
});
};
server.listen(port,host,function(){
console.log(`Server started on port ${port} at ${host}`);
});
However I'm looking to extend this device/server interaction to a web portal from where I want to send/receive data from the device in real-time and I can't seem to wrap my head around how to approach this problem. Is it possible to do this? The device itself is a low-end device that don't seem to have a embedded web server. Can we create a REST API like interface between the web portal and TCP server to accomplish this task? I'm really lost. Any pointers?
Please help.

Socket.io connection event not fired on server

I am trying to build a command-line chat room using Node.js and Socket.io.
This is my server-side code so far, I have tried this with both http initialisations (with express, like on the official website's tutorial, and without it):
#app = require('express')()
#http = require('http').Server(app)
http = require('http').createServer()
io = require('socket.io')(http)
io.sockets.on 'connect', (socket) ->
console.log 'a user connected'
http.listen 3000, () ->
console.log 'listening on *:3000'
I start this with nodejs server.js, the "Listening on" is showing up.
If I run lsof -i tcp:3000, the server.js process shows up.
However, when I start this client-side code:
socket = require('socket.io-client')('localhost:3000', {})
socket.on 'connect', (socket) ->
console.log "Connected"
No luck... When I run nodejs client.js, neither "connect" events, from server nor client, are fired!
My questions are :
- What am I doing wrong?
- Is it necessary to start a HTTP server to use it? Sockets are on the transport layer, right? So in theory I don't need a HTTP protocol to trade messages.
If this is a server to server connection and you're only making a socket.io connection (not also setting it up for regular HTTP connections), then this code shows the simple way for just a socket.io connection:
Listening socket.io-only server
// Load the library and initialize a server on port 3000
// This will create an underlying HTTP server, start it and bind socket.io to it
const io = require('socket.io')(3000);
// listen for incoming client connections and log connect and disconnect events
io.on('connection', function (socket) {
console.log("socket.io connect: ", socket.id);
socket.on('disconnect', function() {
console.log("socket.io disconnect: ", socket.id);
});
});
Node.js socket.io client - connects to another socket.io server
// load the client-side library
const io = require('socket.io-client');
// connect to a server and port
const socket = io('http://localhost:3000');
// listen for successful connection to the server
socket.on('connect', function() {
console.log("socket.io connection: ", socket.id);
});
This code works on my computer. I can run two separate node.js apps on the same host and they can talk to one another and both see the connect and disconnect events.
Some Explaining
The socket.io protocol is initiated by making an HTTP connection to an HTTP server. So, anytime you have a socket.io connection, there is an HTTP server listening somewhere. That HTTP connection is initially sent with some special headers that indicate to the server that this is a request to "upgrade" to the webSocket protocol and some additional security info is included.
This is pretty great reference on how a webSocket connection is initially established. It will show you step by step what happens.
Once both sides agree on the "upgrade" in protocol, then the protocol is switched to webSocket (socket.io is then an additional protocol layer on top of the base webSocket protocol, but the connection is all established at the HTTP/webSocket level). Once the upgrade is agreed upon, the exact same TCP connection that was originally the incoming HTTP connection is repurposed and becomes the webSocket/socket.io connection.
With the socket.io server-side library, you can either create the HTTP server yourself and then pass that to socket.io or you can have socket.io just create one for you. If you're only using socket.io on this server and not also sharing using http server for regular http requests, then you can go either way. The minimal code example above, just lets socket.io create the http server for you transparently and then socket.io binds to it. If you are also fielding regular web requests from the http server, then you would typically create the http server first and then pass it to socket.io so socket.io could bind to the http server you already have.
Then, keep in mind that socket.io is using the webSocket transport. It's just some additional packet structure on top of the webSocket transport. It would akin to agreeing to send JSON across an HTTP connection. HTTP is the host transport and underlying data format. Both sides then agree to format some data in JSON format and send it across HTTP. The socket.io message format sits on top of webSocket in that way.
Your Questions
Is it necessary to start a HTTP server to use it?
Yes, an HTTP server must exist somewhere because all socket.io connections start with an HTTP request to an HTTP server.
Sockets are on the transport layer, right?
The initial connection protocol stack works like this:
TCP <- HTTP protocol
Then, after the protocol upgrade:
TCP <- webSocket <- socket.io
So after the protocol upgrade from HTTP to the webSocket transport, you then have socket.io packet format sitting on top of the webSocket format sitting on top of TCP.
So in theory I don't need a HTTP protocol to trade messages.
No, that is not correct. All connections are initially established with HTTP. Once the upgrade happens to the webSocket transport, HTTP is no longer used.

Receiving specific TCP commands with nodejs and handling them

I have a device in my local that sends JSON data through TCP:
ex. {"cmd": "listactions", "id": 13, "value": 100}
The data is send from 192.168.0.233 on port 8000
(I've checked this with wireshark)
I would like to (with my homeserver) intercept those specific commands with nodejs & send them through with pusher.
I have very little experience with nodejs & can't seem to get this working. I tried the following:
net = require('net');
var server = net.createServer(function(sock) {
sock.setEncoding('utf8');
sock.on('data', function (data) {
// post data to a server so it can be saved and stuff
console.log(data);
// close connection
sock.end();
});
sock.on('error', function (error) {
console.log('******* ERROR ' + error + ' *******');
// close connection
sock.end();
});
});
server.on('error', function (e) {
console.log(e);
});
server.listen(8000, '192.168.0.233', function(){
//success, listening
console.log('Server listening');
});
But it complaints about EADDRNOTAVAIL, from research I've learned that this means the port is in use... Which I don't understand because I'm able to with Wireshark.
What's the correct way to do this?
Wireshark doesn't listen on all ports. It uses a kernel driver (with libpcap or winpcap) to "sniff" data off the wire. That is, it doesn't sit in between anything. It's not a man-in-the-middle. It just receives a copy of data as it is sent along.
Your application needs to listen on that port if you expect it to receive data. You should use netstat to figure out what process is listening on port 8000 and kill it. Then, you can listen on port 8000.
You could in theory use libpcap to get your data but that's crazy. There is a ton of overhead, something has to listen on that port anyway (it's a TCP connection after all), and it's extremely complex to filter out what you want. Basically, you would be reimplementing the network stack. Don't.

How to connect to a telnet server from node using socket.io

I may not be entering the correct search terms but I cannot seem to find good examples that allow my node application to initiate a socket.io client connection to another telnet server (non-node).
Below is my node app trying to connect to a telnet server
var ioc = require('socket.io-client'),
clientSocket = ioc.connect('192.168.1.97', {
port: 23
});
clientSocket.on('connect', function(){
console.log('connected to to telnet');
});
clientSocket.on('connect_error', function(data){
console.log('connection error to telnet');
console.log(data);
});
clientSocket.on('connect_timeout', function(data){
console.log('connection timeout to telnet');
console.log(data);
});
Here is the error I get
connection error to telnet
timeout
connection timeout to telnet
20000
I've telneted directly to the telnet server successfully from the terminal. Bad code?
You can't.
Socket.IO has nothing to do with regular TCP network sockets. Socket.IO is an RPC layer providing web-socket-like functionality over several transports (Web Sockets, long-polling AJAX, etc.). You can't just connect to any server you want, you must connect to a Socket.IO server. Even Web Sockets itself has a whole protocol built on top of HTTP that must be set up.
If you want to connect to an arbitrary server to send/receive data, that connection must be proxied server-side through your Node.js application. Socket.IO is only for communication between a Socket.IO client and a Socket.IO server.
Not Sure if this can be done, but have a look at this package
https://www.npmjs.org/package/node-telnet-client

Nodejs: websocket routing based on URL without port proxying

I am trying to do a game in html5 with serverside logic in node.js and that uses raw websockets (not Socket.IO, I need binary data). I wish to have multiple "rooms", thus multiple websocket servers, all having separate URLs. Currently, I only found a way to have each websocket server attached to a specific port, and then proxy the upgrade requests(not entirely sure how it works) to the right port based on the url.
It works on my computer. The problem is that when I try to submit it to a PaaS provider (AppFog), the code fails because they don't permit opening any ports other than the provided http port.
Here is a pretty cleared up version of my code:
//start web server (basic static express server) on 8080
// ...
//start game server and listen to port 9000
// I use the ws module for websockets
// I plan to have a couple of these "game servers"
// ...
//open the proxy server.
var httpProxy= require('http-proxy');
var webProxyServer = httpProxy.createServer(function (req, res, proxy){
// I need http requests to be redirected to the "game servers"
if(req.url.substring(0, "/room1".length) === "/room1") // if starts with "/room1"
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
else
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8080
});
}
webProxyServer.on('upgrade', function (req, socket, head) {
//redirecting logic goes here
if(req.url=="/room1/"){
webProxyServer.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: 9000
})
}
});
webProxyServer.listen(8000); //the "outside port".
My question: is it somehow possible to open websocket servers without listening to any specific ports, and to manually attach sockets to them so I don't need to open any ports other than the basic http port? I know Socket.IO somehow does it. Maybe there is a way to listen to the upgrade event of a http server and pass the socket to the right websocket server?
I am pretty new to server-side stuff, so extra info here and there would be welcome.
Unfortunately, Appfog does not support websockets.
Feature Roadmap page - bottom of page: shows websockets as something coming soon (i.e. they don't support it).

Resources