In Node.js (running on Windows) how to get the domain name - node.js

I have requirement where my NodeJS http server (on Windows) has to listen on the hostname instead of localhost/127.0.0.1.
For this I need the full hostname (including the domain name) of my Windows machine and I am not able to get the full hostname.
I tried using
require('os').hostname()
but it does not give me the full hostname.
So I tried the below:
var dns = require('dns');
var os = require('os');
var hostname = os.hostname();
console.log("Short hostname = ", hostname);
dns.lookup(hostname, function (err, add, fam) {
if (err)
{
console.log("The error = ", JSON.stringify(err));
return;
}
console.log('addr: '+add);
console.log('family: ' + fam);
dns.reverse(add, function(err, domains){
if (err)
{
console.log("The reverse lookup error = ", JSON.stringify(err));
return;
}
console.log("The full domain name ", domains);
});
})
The above code works fine and I get the below output when I am on the ethernet of my enterprise
C:\>node getFullHostname.js
Short hostname = SPANUGANTI
addr: 16.190.58.214
family: 4
The full domain name [ 'spanuganti.abc.xyz.net' ]
But the same code does not work when I am connected to the wireless network of the enterprise
C:\>node getFullHostname.js
Short hostname = SPANUGANTI
addr: 16.183.204.47
family: 4
The reverse lookup error =
{"code":"ENOTFOUND","errno":"ENOTFOUND","syscall":"getHostByAddr"}
So need help on the below
Is there a simple way to get the full machine name (Windows) in Node.js
Or please let me know what is the problem with my code above

Servers don't listen on hostnames, they listen on IP addresses. You should never rely on the contents of the external DNS to figure out where to bind.
The easiest solution is to have it bind to the INADDR_ANY address, which is numerically equivalent to 0.0.0.0.
This would then allow queries on any interface, including the loopback.

You don't need the full hostname to listen on, you actually need your IP address. Check out the os.networkInterfaces() function.

Related

net module "socket.remoteAddress" value is wrong

I create a TCP IVP4 socket server in Node.js using the 'net' module, and it works great for almost all of my clients, but one client has an IP similar to (I won't disclose the real one):
180.190.154.97
but when they connect to my socket server and I console.log(socket.remoteAddress), the value is this:
180.190.193.2
Why would this be happening?
// Import dependencies
let net = require('net')
// Create socket server.
const SERVER = net.createServer(socketConnection)
function socketConnection(client) {
console.log(client.remoteAddress)
}
// Server code snippet
let SERVER_LISTEN_ADDRESS = '0.0.0.0'
if (Game.local) {
SERVER_LISTEN_ADDRESS = '127.0.0.1'
Game.port = 42480
}
SERVER.listen(Game.port, SERVER_LISTEN_ADDRESS, () => {
console.log('Listening on port ' + Game.port)
if (!Game.local)
postServer()
else
console.log('Running server locally.')
})
Expected result is that it should print their IPV4 value from a site like:
https://whatismyipaddress.com/
But instead it says something completely different.
The result shown by whatipmyaddress it is not always the public IP of the single host. It could be rather also the IP of the subnet or if there's a proxy the IP of the proxy server. The fact that the address differs by a few units suggests that those particular hosts are in a subnet where a NAT service is active, or protected by a proxy or where the router acts as a VPN to the outside, encapsulating and sending the message to the server. In this case probably the entire subnet is seen as a single host.
In case you're using Express, you may want to use request-ip package in order to retrieve the IP in a more robust way. Since it seems you're not using express you should implement something similar to the first example shown in the link. For your specific case according the code you give:
const requestIp = require('request-ip');
function socketConnection(client) {
const clientIp = requestIp.getClientIp(client);
console.log(client);
}

Using socket.io from inside and outside LAN

I am using socket.io for a project that requires me to stream live data to a browser. Now the server part is fine, but on socket.io client io.connect() call, I have had a few problems in the past, without proper resolution. I have tried the usual suspects, but I am not getting through.
My client call to looks like this:
var socket = io.connect('http://10.95.xx.xx:5002');
where 10.95. .. is the IP address of the server on the LAN. Using this IP I can access the server from inside the LAN, on any machine in the LAN, but this doesn't work from outside the LAN. Problem being, most probably, that this IP is for LAN only and not the public IP. As per university's network settings, the public IP is 128.95 ...and if I change it to this IP, then it will be accessible from outside, but not from inside.
One way to resolve this, is that I try to read the client's IP address and based on that decide the parameter IP. But this doesn't feel robust. Also, I tried using io.connect("/") . It had worked for me in previous circumstance, but it did not this time. Also, the empty call did not work io.connect() did not work.
As you said you can use the clients IP address, this here always worked for me:
var port = window.location.port,
host = window.location.hostname,
protocol = window.location.protocol,
path = '/',
url,
options = { };
if( protocol.indexOf( 'https' ) > -1 ) {
protocol = 'wss:';
} else {
protocol = 'ws:'
}
url = protocol + "//" + host + ":" + port + path;
options = { };
/*
// If you wanted to add an access token, "Session" is where I store this
if( Session.token ) {
options.query = 'access_token=' + Session.token;
}
*/
socket = io( url, options );

Stripping "::ffff:" prefix from request.connection.remoteAddress nodejs

I am implementing subscription/response possibility using nodejs (express). When visitor send request, beside other parameters within request (port, time interval etc...) I am going to collect ip in order to be able to send response to that ip from time to time.
I am fetching visitor ip address using folowing:
var ip = req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
based on How can I get the user's IP address using Node.js?
Point is that after i get ip I have something like this : "::ffff:192.168.1.10" (explained at request.connection.remoteAddress Now Prefixed in ::ffff in node.js )
I am wondering, is it "safe" just to strip "::ffff:" prefix in order to get ip address which I will be able to use in order to reply via http response, or I am missing something else over here, and that is not what i should do?
Yes, it's safe to strip. Here's a quick way to do it.
address.replace(/^.*:/, '')
What happens is your OS is listening with a hybrid IPv4-IPv6 socket, which converts any IPv4 address to IPv6, by embedding it within the IPv4-mapped IPv6 address format. This format just prefixes the IPv4 address with :ffff:, so you can recover the original IPv4 address by just stripping the :ffff:. (Some deprecated mappings prefix with :: instead of :ffff:, so we use the regex /^.*:/ to match both forms.)
If you aren't sure that incoming IPv6 address came from an IPv4, you can check that it matches the IPv6-mapping template first:
template = /^:(ffff)?:(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|$)){4}$/
has_ipv4_version = template.test(address)
If you want to get the ip address of IPv4, you can use:
http.createServer(callback).listen(port, '0.0.0.0');
then, you will get what you want
req.connection.remoteAddress // 192.168.1.10
Here is the relevant document of nodejs
app.post('/xyz',function(request,response)
{
var IPFromRequest=request.connection.remoteAddress;
var indexOfColon = IPFromRequest.lastIndexOf(':');
var IP = IPFromRequest.substring(indexOfColon+1,IPFromRequest.length);
console.log(IP);
});
I would split the remoteAddress ::ffff:192.168.1.10 by the : delimiter and simply take the value of the output array at index array.length - 1
like so:
const remoteAddress = '::ffff:192.168.0.3'
const array = remoteAddress.split(':')
const remoteIP = array[array.length - 1]
console.log(remoteIP)
prints out 192.168.0.3
This node code ...
returns ipv6 to ipv4 IF the ipv6 address is really a mapped ipv4 address
else it returns a normalised ipv6 address
else it just returns the ip string it originally had
var ip = (function (req) {
var ipaddr = require('ipaddr.js');
var ipString = (req.headers["X-Forwarded-For"] ||
req.headers["x-forwarded-for"] ||
'').split(',')[0] ||
req.connection.remoteAddress;
if (ipaddr.isValid(ipString)) {
try {
var addr = ipaddr.parse(ipString);
if (ipaddr.IPv6.isValid(ipString) && addr.isIPv4MappedAddress()) {
return addr.toIPv4Address().toString();
}
return addr.toNormalizedString();
} catch (e) {
return ipString;
}
}
return 'unknown';
}(req));
https://www.npmjs.com/package/ipaddr.js
https://github.com/whitequark/ipaddr.js
Just to add onto the answer provided by Michael Matthew Toomim,
If you want to test to see if the IP is an IPv4 address mapped as an IPv6, you will probably want to adjust the regex to this:
/^:{1,2}(ffff)?:(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|$)){4}$/
The difference being /^:{1,2} instead of /^:, which allows for both addresses which start with ::ffff: and :ffff:.
Had the same problem...im also new at javascript but i solved this with .slice
var ip = req.connection.remoteAddress;
if (ip.length < 15)
{
ip = ip;
}
else
{
var nyIP = ip.slice(7);
ip = nyIP;
}
req.connection.remoteAddress.substring(7,req.connection.remoteAddress.length)

Can not send back UDP to internal PC behide NAT

I setup two PC,
one is client in local network behide NAT,
another is server on public network.
The test steps are --
1) client listen udp on port 33333
2) server listen udp on port 22222
1) client send udp to server
2) server received the data and send back
When I test the code on my test network, it's OK.
If put the server on real internet, server can get the message from client,
client can not get response from server.
What's wrong?
Here's testing code with nodejs.
server
var dgram = require('dgram');
var socket = dgram.createSocket('udp4');
socket.on('message', function (message, remote) {
console.log('client ip:' + remote.address + ', port:' + remote.port +', message:' + message);
//send response to client
var message = new Buffer("hello, client!");
socket.send(message, 0, message.length, remote.port, remote.address);
});
//listening port
socket.bind(22222);
client
var dgram = require('dgram');
var socket = dgram.createSocket('udp4');
socket.on('message', function (message, remote) {
//display message from server
console.log('server ip:' + remote.address + ', port:' + remote.port +', message:' + message);
});
//listening port
socket.bind(33333);
//send message to server
function send(server){
var message = new Buffer("hello, server!");
socket.send(message, 0, message.length, 22222, server, function(){
//send again after 1 seconds
setTimeout(function(){
send(server);
}, 1000);
});
};
//suppose that server address is public.server.com
send("public.server.com");
NATed computers cannot be reached from outside and this is particularly painful for peer-to-peer or friend-to-friend software. Basically because your PC has not a public IP address but you NAT device has. So, the NAT is visible, your PC isn't.
The server gets the package from the NAT device and send the response to it. Yes, the NAT receives the response and it has to relay it to your PC, that's the trick. To do so you have to configure a port forwarding in the NAT.
The NAT has a table like the following:
+----------+---------------------+---------------+
| NAT PORT | INTERNAL IP ADDRESS | INTERNAL PORT |
+----------+---------------------+---------------+
| 33333 | 198.162.0.3 (pc ip) | 33333 |
It can be read as: when NAT receives a package in its port #33333 it has to redirected to the internal IP 198.162.0.3 (your PC IP address) and port# 33333.
If your PC uses a fixed IP, you can do this mapping by hand in your NAT. However, if you use a DHCP server, your PC's IP can change after each reboot so you need to do this mapping by software in you project. Most of the NATs support Universal Plug & Play, Port Mapping Protocol or Port Control Protocol to achieve this mapping and you can do it with nodejs given that all you need are the appropiated HTTP request to the NAT.
Yes, you can do it by yourself but it is not so easy. In fact, the discovery process requires you broadcast udp messages in the LAN in specific port. I strongly recommend you to use a third-party component to do it.
I hope this helps you.

Non-http TCP connection on Cloudfoundry

I'm a nooby mobile developer trying to take advantage of cloudfoundry's service to run my server to handle some chats and character movements.
I'm using Noobhub to achieve this (TCP connection between server and client using Node.js and Corona SDK's TCP connection API)
So basically I'm trying a non-http TCP connection between Cloudfoundry(Node.js) and my machine(lua).
Link to Noobhub(There is a github repo with server AND client side implementation.
I am doing
Client
...
socket.connect("myappname.cloudfoundry.com", 45234)
...
(45234 is from server's process.env.VCAP_APP_PORT value I retrieved from console output I got through "vmc logs myappname" after running the application.)
Server
...
server.listen(process.env.VCAP_APP_PORT)
When I try to connect, it just times out.
On my local machine, doing
Client
...
socket.connect("localhost",8989)
Server
...
server.listen(8989)
works as expected. It's just on cloudfoundry that it doesn't work.
I tried a bunch of other ways of doing this such as setting the client's port connection to 80 and a bunch of others. I saw a few resources but none of them solved it.
I usually blow at asking questions so if you need more information, please ask me!
P.S.
Before you throw this link at me with an angry face D:< , here's a question that shows a similar problem that another person posted.
cannot connect to TCP server on CloudFoundry (localhost node.js works fine)
From here, I can see that this guy was trying to do a similar thing I was doing.
Does the selected answer mean that I MUST use host header (i.e. use http protocol) to connect? Does that also mean cloudfoundry will not support a "TRUE" TCP socket much like heroku or app fog?
Actually, process.env.VCAP_APP_PORT environment variable provides you the port, to which your HTTP traffic is redirected by the Cloud Foundry L7 router (nginx) based on the your apps route (e.g. nodejsapp.vcap.me:80 is redirected to the process.env.VCAP_APP_PORT port on the virtual machine), so you definitely should not use it for the TCP connection. This port should be used to listen HTTP traffic. That is why you example do work locally and do not work on Cloud Foundry.
The approach that worked for me is to listen to the port provided by CF with an HTTP server and then attach Websocket server (websocket.io in my example below) to it. I've created sample echo server that works both locally and in the CF. The content of my Node.js file named example.js is
var host = process.env.VCAP_APP_HOST || "localhost";
var port = process.env.VCAP_APP_PORT || 1245;
var webServerApp = require("http").createServer(webServerHandler);
var websocket = require("websocket.io");
var http = webServerApp.listen(port, host);
var webSocketServer = websocket.attach(http);
function webServerHandler (req, res) {
res.writeHead(200);
res.end("Node.js websockets.");
}
console.log("Web server running at " + host + ":" + port);
//Web Socket part
webSocketServer.on("connection", function (socket) {
console.log("Connection established.");
socket.send("Hi from webSocketServer on connect");
socket.on("message", function (message) {
console.log("Message to echo: " + message);
//Echo back
socket.send(message);
});
socket.on("error", function(error){
console.log("Error: " + error);
});
socket.on("close", function () { console.log("Connection closed."); });
});
The dependency lib websocket.io could be installed running npm install websocket.io command in the same directory. Also there is a manifest.yml file which describes CF deploy arguments:
---
applications:
- name: websocket
command: node example.js
memory: 128M
instances: 1
host: websocket
domain: vcap.me
path: .
So, running cf push from this directory deployed app to my local CFv2 instance (set up with the help of cf_nise_installer)
To test this echo websocket server, I used simple index.html file, which connects to server and sends messages (everything is logged into the console):
<!DOCTYPE html>
<head>
<script>
var socket = null;
var pingData = 1;
var prefix = "ws://";
function connect(){
socket = new WebSocket(prefix + document.getElementById("websocket_url").value);
socket.onopen = function() {
console.log("Connection established");
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log("Connection closed clean");
} else {
console.log("Connection aborted (e.g. server process killed)");
}
console.log("Code: " + event.code + " reason: " + event.reason);
};
socket.onmessage = function(event) {
console.log("Data received: " + event.data);
};
socket.onerror = function(error) {
console.log("Error: " + error.message);
};
}
function ping(){
if( !socket || (socket.readyState != WebSocket.OPEN)){
console.log("Websocket connection not establihed");
return;
}
socket.send(pingData++);
}
</script>
</head>
<body>
ws://<input id="websocket_url">
<button onclick="connect()">connect</button>
<button onclick="ping()">ping</button>
</body>
</html>
Only thing to do left is to enter server address into the textbox of the Index page (websocket.vcap.me in my case), press Connect button and we have working Websocket connection over TCP which could be tested by sending Ping and receiving echo. That worked well in Chrome, however there were some issues with IE 10 and Firefox.
What about "TRUE" TCP socket, there is no exact info: according to the last paragraph here you cannot use any port except 80 and 443 (HTTP and HTTPS) to communicate with your app from outside of Cloud Foundry, which makes me think TCP socket cannot be implemented. However, according to this answer, you can actually use any other port... It seems that some deep investigation on this question is required...
"Cloud Foundry uses an L7 router (ngnix) between clients and apps. The router needs to parse HTTP before it can route requests to apps. This approach does not work for non-HTTP protocols like WebSockets. Folks running node.js are going to run into this issue but there are no easy fixes in the current architecture of Cloud Foundry."
- http://www.subbu.org/blog/2012/03/my-gripes-with-cloud-foundry
I decided to go with pubnub for all my messaging needs.

Resources