How to get the address of the freshly looked up hostname in Node.js? - node.js

I am to write out the freshly looked up IP address of a hostname in Node.js:
var net = require('net');
var sock = net.Socket();
sock.on('lookup', function(e)
{
console.log('DNS lookup');
console.log(address);
} )
...
sock.connect(80, 'google.com');
https://nodejs.org/api/net.html#net_event_lookup
says that the lookup event is
Emitted after resolving the hostname but before connecting. Not applicable to UNIX sockets.
err <Error> | <null> The error object. See dns.lookup().
address <string> The IP address.
family <string> | <null> The address type. See dns.lookup().
host <string> The hostname.
But which object has these fields? I tried them as simple variable names -- did not work, and as fields of the e object possibly passed to the anonymous function that I register for the lookup event -- that also did not work.
How can I access these fields upon lookup?

You get all the params in the callback, see the code below.
var net = require('net');
var sock = net.Socket();
const options = {
host: "google.com",
port: 80
};
sock.connect(options);
sock.on('lookup', function(err, address, family, host) {
console.log(address);
console.log(family);
console.log(host);
console.log(err);
});

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);
}

Node : how to set static port to udp client in node js

I am very new to Udp Socket programming, here i implemented echo UDP Client which connects to UDP server
var buffer = require('buffer');
var udp = require('dgram');
// creating a client socket
var client = udp.createSocket('udp4');
//buffer msg
var data = Buffer.from('Pradip Shinde');
client.on('message',function(msg,info){
console.log('Data received from server : ' + msg.toString());
console.log('Received %d bytes from %s:%d\n',msg.length, info.address, info.port);
});
//sending msg
client.send(data,9300,'192.168.1.187',function(error){
if(error){
client.close();
}else{
console.log('Data sent from client!!!');
}
});
when this client send msg to server, operating system assign the random port to this client but in my scenario i want static port which will never change, is it possible to assign static port to udp client?
As mentioned in the documentation, you can use bind method to do this,
For UDP sockets, causes the dgram.Socket to listen for datagram messages on a named port and optional address that are passed as properties of an options object passed as the first argument. If port is not specified or is 0, the operating system will attempt to bind to a random port. If address is not specified, the operating system will attempt to listen on all addresses. Once binding is complete, a 'listening' event is emitted and the optional callback function is called.
Try using
// Creating a client socket
var client = udp.createSocket('udp4');
// Bind your port here
client.bind({
address: 'localhost',
port: 8000,
exclusive: true
});
For more information follow this documentation.

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)

Node JS TCP Proxy: Reuse socket in callback function

I'm trying to implement a TCP proxy in Node JS. I only have some experience with Javascript so I met a lot of problems along the way. I've done a lot of searching for this one but had no luck.
The problem occurs when browser sends a CONNECT request for HTTPS. My proxy will parse the host name and port, and then create a new socket that connects to the server. If all these steps went well, I will start forwarding message.
Part of my code looks like this:
var net = require('net');
var server = net.createServer(function(clientSock) {
clientSock.on('data', function(clientData) {
var host = // get from data
var port = // get from data
if (data is a CONNECT request) {
// Create a new socket to server
var serverSock = new net.Socket();
serverSock.connect(port, host, function() {
serverSock.write(clientData);
clientSock.write('HTTP/1.1 200 OK\r\n');
}
serverSock.on('data', function(serverData) {
clientSock.write(serverData);
}
}
}
}
Since the CONNECT request needs both client socket and server socket open until one side closes the connection, the code above doesn't have this behavior. Every time I receive some data from client, I will create a new socket to server and the old one is closed.
Is there a way to store the server socket as a global variable so that the data event handler can reuse it? Or is there any other way to solve this?
Thanks a lot!!!!
You can just move the variable up to a higher scope so it survives across multiple events and then you can test to see if its value is already there:
var net = require('net');
var server = net.createServer(function(clientSock) {
var serverSock;
clientSock.on('data', function(clientData) {
var host = // get from data
var port = // get from data
if (data is a CONNECT request) {
// Create a new socket to server
if (!serverSock) {
serverSock = new net.Socket();
serverSock.connect(port, host, function() {
serverSock.write(clientData);
clientSock.write('HTTP/1.1 200 OK\r\n');
}
serverSock.on('data', function(serverData) {
clientSock.write(serverData);
}
} else {
serverSock.write(clientData);
}
}
}
}

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

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.

Resources