IP reported as null in Node.jsExpress...how is that possible? - node.js

I have a website with a Node.js/Express backend and I need to log the visitor's IP address. It seems this should be a fairly straightforward process, however I am having continuous difficulty with it. My code is similar:
const express = require('express');
const app = express();
var port = 443;
app.get('/', function (req, res) {
var site = req.hostname; //example returns "localhost" from "localhost:8080"
var splits = site.split("."); //"split" on "periods"
var subdomain = String(splits[1])
var _host = req.headers.host;
var _userIP = req.headers['x-forwarded-for'] || req.socket.remoteAddress || null;
console.log('_userIP is: ', _userIP); //returns 'null'
//...
});
//...
// Start server...
var webServer = app.listen(process.env.PORT || port, function(request, response) { console.log(" Received request for " + new Date()); } );
console.log('Listening on port ' + port);
//...
console.log("***CREATING WEBSOCKET SERVER");
var wsServer = new WebSocketServer({
httpServer: webServer,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
For guidance I am using the following source for information: "https://stackoverflow.com/questions/8107856/how-to-determine-a-users-ip-address-in-node".
My console.log statement returns "null" as the value for the '_userIP' variable...why??? As I understand ANY connection made to the server should have some sort of IP address, correct? If that is the case then the 'null' as my 'fallback' variable definition should never be assigned, however it is...
Any advice is greatly appreciated.
BTW I have also attempted assigning the '_userIP' variable to "req.ip" as:
console.log('_userIP is: ', req.ip);
...without success. I believe it returned 'undefined' if I remember correctly.
I have also tried:
_userIP = req.header('x-forwarded-for') ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
This code throws an error, I believe because the 'req.connection.socket.remoteAddress' is deprecated...?
If it makes a difference I believe this code displays "::1" if it is run on localhost...which indicates it is functional. Why would the code fail to display a user IP address when executed on a 'real' server? Is it possible my server software (Plesk) may be somehow blocking the IP address?

Related

Request.headers missing or undefined

Hopefully somebody will find this a relatively simple answer, but it is beyond me at the moment. I have a Node.js/Express setup. I am simply trying to retrieve the client IP address upon each request to the site. My code is as follows:
const express = require('express');
const app = express();
const port = 3000;
...
// Start server...
var webServer = app.listen(process.env.PORT || port, function(request, response) {
console.log(" Received request for " + new Date());
var _FORWARD_IP = request.headers['x-forwarded-for'];
console.log('_FORWARD_IP (CLIENT IP ADDRESS): ' + _FORWARD_IP);
});
However this throws the following error:
"TypeError: Cannot read property 'headers' of undefined"
Therefore it seems there are no headers in the 'request' object within the 'app.listen' command. I am unsure how to resolve, this is the initial instance of dealing with something like this. If anybody knows an answer or a workaround it is greatly appreciated. I thank you in advance.
Regards
app.listen() just starts the server, telling it to listen for requests. There is no request at that point in your code.
This sounds like a job for some custom middleware
const port = process.env.PORT || 3000;
// Middleware
app.use((req, res, next) => {
const _FORWARD_IP = req.get('x-forwarded-for');
console.log('_FORWARD_IP (CLIENT IP ADDRESS):', _FORWARD_IP);
next();
});
app.listen(port, () => {
// This callback executes when the server is ready to accept connections
console.info(`Express server started on port ${port}`);
});

Why Does Express Always Return the Local IP Address?

What I am trying to do is to get the client's IP address. I have attempted two different ways to do so. However, when I send a GET request to the endpoint (root) through Postman, both return ::1, which is the local IP address. With this regard, I am wondering if I could get my own IP address (192.XXX.XXX.XXX) in development. To me, getting back ::1 does not make sense because even though Express is upon running on local, the IP address of the request from Postman should be my own IP Address. Could anyone please explain to me why this happens? If you could also tell me how I can get back my own IP address from Express, that would be appreciated. My code for the implementation is the following:
import express from 'express'
import cors from 'cors'
const port = process.env.PORT || 9000
const app = express()
app.use(express.json())
app.use(cors())
//method 1
app.get('/', (req, res) => {
const ip = req.ip;
//const ip = getIP
res.status(200).send(ip)
})
//method 2
const getIP = (req) => {
return request.headers['x-forwarded-for']
? request.headers['x-forwarded-for']
: (request.connection && request.connection.remoteAddress)
? request.connection.remoteAddress
: (request.connection.socket && request.connection.socket.remoteAddress)
? request.connection.socket.remoteAddress
: (request.socket && request.socket.remoteAddress)
? request.socket.remoteAddress
: '0.0.0.0';
}
app.listen(port, () => console.log(`listening on localhost: ${port}`))

Node simple http app respond 2 times

I trying to find my way into node.js transfering a local sports statistics application written in c#.
Writing the http server, i observe that every time i refresh (after the first time) the server to make a new request, i have 2 response.
I strip the code to eliminate every other possible cause and the "problem" still exists.
Code
var http = require("http");
var counter = 0;
var port = process.env.PORT || 3000;
var requestListener = function (req, res) {
counter += 1;
res.end("Hits: "+ counter);
};
var server = http.createServer(requestListener);
server.listen(port, function (err) {
console.log("server listen on port " + port);
});
Is this the normal behaviour or i missing something?
In a browser page, this is often caused by the browser requesting your page and then requesting some other resource from the same host (such as the favicon for the page). You can see exactly what is being requested to shine some light on what's happening by logging req.url:
var http = require("http");
var counter = 0;
var port = process.env.PORT || 3000;
var requestListener = function (req, res) {
// add logging for what url is being requested
console.log(req.url);
counter += 1;
res.end("Hits: "+ counter);
};
var server = http.createServer(requestListener);
server.listen(port, function (err) {
console.log("server listen on port " + port);
});
Is this the normal behaviour or i missing something?
This is normal and expected. If the extra request turns out to be a favicon request, then you can disable that as explained here: How to prevent favicon.ico requests?
Note: it is a bit unusual to have a web server that does not even look at the requesting URL and does the same thing no matter what path request was sent to it. If you were looking at the URL and branching your code based on the URL, you would likely be avoiding requests that you were not expecting.

Issues with Socket.IO with Chrome and Firefox

Another update:
The problem occurs when running on localhost as well. Since I figured out the problem comes from the proxy server, here's its code :
var serverBouncer = bouncy(function(req, res, bounce) {
var path = req.url;
var url = req.headers.host;
if (typeof url !== "string")
return;
var urlArray = url.split('.');
var bouncePort = port;
if (!isNaN(urlArray[0]))
bouncePort = parseInt(urlArray[0]);
else if (String(urlArray[0]).toLowerCase() === "www" && !isNaN(urlArray[1]))
bouncePort = parseInt(urlArray[1]);
bounce(bouncePort);
});
serverBouncer.listen(80);
Update:
I found where the problem came from!!! But I still need to find the solution... There seems to be issues with using newer versions of Socket.io (>= 1.0) with a proxy server (bouncy, in my case).
I recently updated Socket.IO from v0.9.16 to v1.4.5, as well as adding Express to the mix. However, now I cannot open multiple (number seems to vary) tabs in Chrome and Firefox without experiencing strange issues (Edge is the only one to work well). It either hangs, or partially loads html and other resources before it hangs.
After waiting, I often get the error :
Failed to load resource: the server responded with a status of 400 (Bad Request)
When I close one of the tab that's been hanging, it unblocks the other tabs that were also hanging.
The issues were not present before going through with the changes listed above.
I've been doing research for 2 full days and just now decided to post this, as I know it's very vague and I'm probably not providing enough information. As much as I'd like to, it would take a very long time to remember and list everything I tried during that time.
Using Windows 10 with Chrome v51.0.2704.103, Firefox v43.0.1. The server (CentOS) is using node v6.2.2 with mainly the following modules :
express#4.14.0
npm#3.9.5
socket.io#1.4.5
Here's some relevant server code :
var port = 8502;
var socketio = require('socket.io');
var express = require("express");
var http = require('http');
var app = express();
var server = http.createServer(app);
var io = socketio.listen(server);
server.listen(port);
app.get('/', function(req, res, next) {
//Returning index.html
});
io.on("connection", function(socket) {
//Some events...
});
Here's a bit of the client code :
var client = io.connect();
client.on('connect', function() {
//Some events
})
your binding before the server is listening, try something like this
var app = express();
server = app.listen(PORT, function () {
console.log('Example app listening on port ' + PORT + '!');
});
io.listen(server);
I managed to replace the bouncy module with nginx. See my other question for the solution.
nginx : redirect to port according to domain prefix (dynamically)

How do you create a dns server for wildcard domains on localhost for use with node/express?

I would like to create a local https server using express that handles any subdomain of example.com. Ideally I would like to modify my hosts file like this:
127.0.0.2 localhost *.example.com
but this is not allowed.
So I would like to create my own dns server to resolve the IP for *.example.com to 127.0.0.2. I have looked at https://github.com/tjfontaine/node-dns and https://github.com/iriscouch/dnsd but I don't understand how to apply them to my scenario.
xip.io may not work for you, but I've found it to be extremely useful. "xip.io is a magic domain name that provides wildcard DNS for any IP address." "xip.io runs a custom DNS server on the public Internet. When your computer looks up a xip.io domain, the xip.io DNS server extracts the IP address from the domain and sends it back in the response."
So all of the following domains will resolve to 127.0.0.1:
127.0.0.1.xip.io
www.127.0.0.1.xip.io
example.com.127.0.0.1.xip.io
something.example.com.127.0.0.1.xip.io
(The daemon happens to be written in Coffeescript to run on node.js.)
You will need to run a local DNS server to intercept the requests.
I have found dnsproxy.py to work quite well. It is written in python and needs to be running while you intend on using it.
You will need to edit your hosts file and add a line like this:
127.0.0.1 *.example.com
After that you will need to start the DNS proxy server:
$ sudo python dnsproxy.py -s 8.8.8.8
8.8.8.8 is the IP address of Google's DNS servers that will be used as a fallback if the record is not found in the hosts file.
Once you have done this, you should be able to start an express server on port 80 and handle requests to *.example.com.
There were some things that were tripping me up that I have worked through.
I wasn't setting up the DNS server IP address in the Network setting of my machine.
I had a timing issue between starting the DNS server and starting the https server.
I wasn't including a port number in the DNS response
Here is my solution:
var fs = require('fs');
var path = require('path');
var dns = require('native-dns');
var https = require('https');
var express = require('express');
String.prototype.endsWith = function(s) {
return this.length >= s.length && this.substr(this.length - s.length) == s;
};
var startDns = function(example_port, callback) {
var server = dns.createServer();
server.on('request', function(request, response) {
var found = false;
for (var q = 0; q < request.question.length; q++)
{
var name = request.question[q].name;
if (name.endsWith("example.com"))
{
response.answer.push(dns.A({
name:name,
address:'127.0.0.2',
port:example_port,
ttl:600
}));
found = true;
}
}
if (found)
{
response.send();
}
});
server.on('error', function(err, buff, req, res) {
console.log(JSON.stringify(err));
});
server.on('listening', function() {
console.log("DNS server started on port 53");
if (callback)
{
callback();
}
});
server.serve(53);
return server;
};
var startHttps = function(serverPort) {
// Set up secure server
var options = {
key:fs.readFileSync(path.join(__dirname, 'certificates/example.com-key.pem')),
cert:fs.readFileSync(path.join(__dirname, 'certificates/example.com-cert.pem'))
};
var app = express();
var server = https.createServer(options, app);
app.get('*', function(req, res, next) {
res.send('Hello from ' + req.headers.host);
});
server.listen(serverPort, 'example.com');
console.log('https server started on port ' + serverPort);
return server;
};
var server_port = parseInt(process.argv[2] || 8082);
var httpsServer;
var dnsServer = startDns(server_port, function() {
httpsServer = startHttps(server_port)
});
process.on('SIGINT', function() {
console.log("shutting down");
if (httpsServer)
{
httpsServer.close();
}
if (dnsServer)
{
dnsServer.close();
}
});
Notes: This is working on my Windows machine. I am still testing on other platforms. I am not sure if I am correctly handling domains in my dns server that aren't recognized.

Resources