Stripping "::ffff:" prefix from request.connection.remoteAddress nodejs - node.js

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)

Related

convert req.connection.remoteAddress to not include :ffff

I have node js application where I am capturing IP address using the following piece of code:
var ip = req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
Here, req.connection.remoteAddress appends ::ffff: before the actual IP.
Is there a standard way to have only the IP returned without the ::ffff: before other than stripping it? Is there some API or something to invoke to do the conversion?
You can use Regular Expressions to capture only what is after the ::ffff::
var reg = /([^f:]+)/;
var str = '::ffff:127.0.0.1';
alert(reg.exec(str)[0]);
You can use ipaddr.js for that:
const ipaddr = require('ipaddr.js');
let mappedAddr = '::ffff:127.0.0.1';
let ipv4Addr = ipaddr.process(mappedAddr).toString(); // -> 127.0.0.1

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

HAProxy + Node.js & Express not forwarding IP address

I'm trying to get HAProxy to pass the user's IP address by using:
option forwardfor
In my haproxy.cnf
But for some reason my express returns no IP address. This is the code I'm using in Node.js:
var usrIP = "0";
if( req.connection.remoteAddress !== null || req.connection.remoteAddress !== "null" || req.connection.remoteAddress.length > 1 ) {
usrIP = req.connection.remoteAddress;
}
Any ideas what could be wrong?
You'll get client IP in headers.
"forwardfor" option which will add an "X-Forwarded-For" header with the
original client's IP address. You must also use "httpclose" to ensure
that you will rewrite every requests and not only the first one of each
session :
option httpclose
option forwardfor
Line 122 http://haproxy.1wt.eu/download/1.2/doc/architecture.txt

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.

How to determine a user's IP address in node

How can I determine the IP address of a given request from within a controller? For example (in express):
app.post('/get/ip/address', function (req, res) {
// need access to IP address here
})
In your request object there is a property called socket, which is a net.Socket object. The net.Socket object has a property remoteAddress, therefore you should be able to get the IP with this call:
request.socket.remoteAddress
(if your node version is below 13, use the deprecated now request.connection.remoteAddress)
EDIT
As #juand points out in the comments, the correct method to get the remote IP, if the server is behind a proxy, is request.headers['x-forwarded-for']
EDIT 2
When using express with Node.js:
If you set app.set('trust proxy', true), req.ip will return the real IP address even if behind proxy. Check the documentation for further information
var ip = req.headers['x-forwarded-for'] ||
req.socket.remoteAddress ||
null;
Note that sometimes you can get more than one IP address in req.headers['x-forwarded-for']. Also, an x-forwarded-for header will not always be set which may throw an error.
The general format of the field is:
x-forwarded-for: client, proxy1, proxy2, proxy3
where the value is a comma+space separated list of IP addresses, the left-most being the original client, and each successive proxy that passed the request adding the IP address where it received the request from. In this example, the request passed through proxy1, proxy2, and then proxy3. proxy3 appears as remote address of the request.
This is the solution suggested by Arnav Gupta with a fix Martin has suggested below in the comments for cases when x-forwarded-for is not set :
var ip = (req.headers['x-forwarded-for'] || '').split(',').pop().trim() ||
req.socket.remoteAddress
Suggestion using modern JS:
processing x-forwarded-for only if set, if so, take the first address
other parameters use optional chaining (?.)
const parseIp = (req) =>
req.headers['x-forwarded-for']?.split(',').shift()
|| req.socket?.remoteAddress
console.log(parseIp(req))
// => 127.0.0.1
If using express...
req.ip
I was looking this up then I was like wait, I'm using express. Duh.
You can stay DRY and just use node-ipware that supports both IPv4 and IPv6.
Install:
npm install ipware
In your app.js or middleware:
var getIP = require('ipware')().get_ip;
app.use(function(req, res, next) {
var ipInfo = getIP(req);
console.log(ipInfo);
// { clientIp: '127.0.0.1', clientIpRoutable: false }
next();
});
It will make the best attempt to get the user's IP address or returns 127.0.0.1 to indicate that it could not determine the user's IP address. Take a look at the README file for advanced options.
You can use request-ip, to retrieve a user's ip address. It handles quite a few of the different edge cases, some of which are mentioned in the other answers.
Disclosure: I created this module
Install:
npm install request-ip
In your app:
var requestIp = require('request-ip');
// inside middleware handler
var ipMiddleware = function(req, res, next) {
var clientIp = requestIp.getClientIp(req); // on localhost > 127.0.0.1
next();
};
Hope this helps
request.headers['x-forwarded-for'] || request.connection.remoteAddress
If the x-forwarded-for header is there then use that, otherwise use the .remoteAddress property.
The x-forwarded-for header is added to requests that pass through load balancers (or other types of proxy) set up for HTTP or HTTPS (it's also possible to add this header to requests when balancing at a TCP level using proxy protocol). This is because the request.connection.remoteAddress the property will contain the private IP address of the load balancer rather than the public IP address of the client. By using an OR statement, in the order above, you check for the existence of an x-forwarded-for header and use it if it exists otherwise use the request.connection.remoteAddress.
Following Function has all the cases covered will help
var ip;
if (req.headers['x-forwarded-for']) {
ip = req.headers['x-forwarded-for'].split(",")[0];
} else if (req.connection && req.connection.remoteAddress) {
ip = req.connection.remoteAddress;
} else {
ip = req.ip;
}console.log("client IP is *********************" + ip);
Warning:
Don't just blindly use this for important rate-limiting:
let ip = request.headers['x-forwarded-for'].split(',')[0];
It's very easy to spoof:
curl --header "X-Forwarded-For: 1.2.3.4" "https://example.com"
In that case ther user's real IP address will be:
let ip = request.headers['x-forwarded-for'].split(',')[1];
I'm surprised that no other answers have mentioned this.
I have tried all of them didn't work though,
console.log(clientIp);
console.log(req.ip);
console.log(req.headers['x-forwarded-for']);
console.log(req.connection.remoteAddress);
console.log(req.socket.remoteAddress);
console.log(req.connection.socket.remoteAddress.split(",")[0]);
When running an Express app behind a proxy for me Nginx, you have to set the application variable trust proxy to true. Express offers a few other trust proxy values which you can review in their documentation, but below steps worked for me.
app.set('trust proxy', true) in your Express app.
app.set('trust proxy', true);
Add proxy_set_header X-Forwarded-For $remote_addr in the Nginx
configuration for your server block.
location / {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr; # this line
proxy_cache_bypass $http_upgrade;
}
You can now read off the client’s IP address from the
req.header('x-forwarded-for') or req.connection.remoteAddress; Full code for ipfilter
module.exports = function(req, res, next) {
let enable = true; // true/false
let blacklist = ['x.x.x.x'];
let whitelist = ['x.x.x.x'];
let clientIp = req.header('x-forwarded-for') || req.connection.remoteAddress;
if (!clientIp) {
return res.json('Error');
}
if (enable
&& paths.some((path) => (path === req.originalUrl))) {
let blacklist = blacklist || [];
if (blacklist.some((ip) => clientIp.match(ip) !== null)) {
return res.json({ status: 401, error: 'Your IP is black-listed !'});
}
let whitelist = whitelist || [];
if (whitelist.length === 0 || whitelist.some((ip) => clientIp.match(ip) !== null)) {
next();
return;
} else {
return res.json({ status: 401, error: 'Your IP is not listed !'});
}
}
next();
};
There are two ways to get the ip address :
let ip = req.ip
let ip = req.connection.remoteAddress;
But there is a problem with above approaches.
If you are running your app behind Nginx or any proxy, every single IP addresses will be 127.0.0.1.
So, the best solution to get the ip address of user is :-
let ip = req.header('x-forwarded-for') || req.connection.remoteAddress;
function getCallerIP(request) {
var ip = request.headers['x-forwarded-for'] ||
request.connection.remoteAddress ||
request.socket.remoteAddress ||
request.connection.socket.remoteAddress;
ip = ip.split(',')[0];
ip = ip.split(':').slice(-1); //in case the ip returned in a format: "::ffff:146.xxx.xxx.xxx"
return ip;
}
In node 10.14 , behind nginx, you can retrieve the ip by requesting it through nginx header like this:
proxy_set_header X-Real-IP $remote_addr;
Then in your app.js:
app.set('trust proxy', true);
After that, wherever you want it to appear:
var userIp = req.header('X-Real-IP') || req.connection.remoteAddress;
If you're using express version 3.x or greater, you can use the trust proxy setting (http://expressjs.com/api.html#trust.proxy.options.table) and it will walk the chain of addresses in the x-forwarded-for header and put the latest ip in the chain that you've not configured as a trusted proxy into the ip property on the req object.
If you're using express.js then,
app.post('/get/ip/address', function (req, res) {
res.send(req.ip);
})
var ipaddress = (req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress).split(",")[0];
If you get multiple IPs , this works for me:
var ipaddress = (req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress).split(",")[0];
Simple get remote ip in nodejs:
var ip = req.header('x-forwarded-for') || req.connection.remoteAddress;
req.connection has been deprecated since node#12.12.0. Using req.connection.remoteAddress to get the client IP might still work but is discouraged.
Luckily, req.socket.remoteAddress has been there since node#0.5.10 and is a perfect replacement:
The string representation of the remote IP address. For example, '74.125.127.100' or '2001:4860:a005::68'. Value may be undefined if the socket is destroyed (for example, if the client disconnected).
There were a lot of great points here but nothing that was comprehensive, so here's what I ended up using:
function getIP(req) {
// req.connection is deprecated
const conRemoteAddress = req.connection?.remoteAddress
// req.socket is said to replace req.connection
const sockRemoteAddress = req.socket?.remoteAddress
// some platforms use x-real-ip
const xRealIP = req.headers['x-real-ip']
// most proxies use x-forwarded-for
const xForwardedForIP = (() => {
const xForwardedFor = req.headers['x-forwarded-for']
if (xForwardedFor) {
// The x-forwarded-for header can contain a comma-separated list of
// IP's. Further, some are comma separated with spaces, so whitespace is trimmed.
const ips = xForwardedFor.split(',').map(ip => ip.trim())
return ips[0]
}
})()
// prefer x-forwarded-for and fallback to the others
return xForwardedForIP || xRealIP || sockRemoteAddress || conRemoteAddress
}
I realize this has been answered to death, but here's a modern ES6 version I wrote that follows airbnb-base eslint standards.
const getIpAddressFromRequest = (request) => {
let ipAddr = request.connection.remoteAddress;
if (request.headers && request.headers['x-forwarded-for']) {
[ipAddr] = request.headers['x-forwarded-for'].split(',');
}
return ipAddr;
};
The X-Forwarded-For header may contain a comma-separated list of proxy IPs. The order is client,proxy1,proxy2,...,proxyN. In the real world, people implement proxies that may supply whatever they want in this header. If you are behind a load balancer or something, you can at least trust the first IP in the list is at least whatever proxy some request came through.
I use this for ipv4 format
req.connection.remoteAddress.split(':').slice(-1)[0]
You can Get User Ip with Express Like this
req.ip
For Example In This case we get the user Ip and send it back to the user With req.ip
app.get('/', (req, res)=> {
res.send({ ip : req.ip})
})
If you are using Graphql-Yoga you can use the following function:
const getRequestIpAddress = (request) => {
const requestIpAddress = request.request.headers['X-Forwarded-For'] || request.request.connection.remoteAddress
if (!requestIpAddress) return null
const ipv4 = new RegExp("(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")
const [ipAddress] = requestIpAddress.match(ipv4)
return ipAddress
}
I'm using express behind nginx and
req.headers.origin
did the trick for me
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
var ip = req.ip
console.log(ip);
res.send('Hello World!')
})
// Run as nodejs ip.js
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
In a shell, you would just curl https://api.ipify.org
So, let's observe this to port it to node.js!
curl is a application to fetch data from websites, we pass the website "https://api.ipify.org" as the argument. We could use node-fetch to replace curl!
The data we get from the website is our IP address, It's some sort of thing which just fetches your IP.
So to sum it up:
const fetch = require('node-fetch');
fetch('https://api.ipify.org')
.then(response => {/* whatever */})
.catch(err => {/* whatever */})
First, install request-ip in your project
import requestIp from 'request-ip';
const clientIp = requestIp.getClientIp(req);
console.log(clientIp)
If you work on localhost, the result might come ::1 because ::1 is real IP Address and is IPV6 notation for localhost.
Using ValidatorJS in Typescript. Here is NodeJS middleware:
// Extract Client IP Address
app.use((req, res, next) => {
let ipAddress = (req.headers['x-forwarded-for'] as string || '').split(',')[0]
if (!validator.isIP(ipAddress))
ipAddress = req.socket.remoteAddress?.toString().split(':').pop() || ''
if (!validator.isIP(ipAddress))
return res.status(400).json({errorMessage: 'Bad Request'})
req.headers['x-forwarded-for'] = ipAddress
next()
})
Here I am assuming all requests should have a valid IP address and hence return a response with code 400 if there is no valid IP address found.
For me using kubernetes ingress (NGINX):
req.headers['x-original-forwarded-for']
Worked like a charm in Node.js
we can check with this code in node js
const os = require('os');
const interfaces = os.networkInterfaces();
let addresses = [];
for (var k in interfaces) {
for (var k2 in interfaces[k]) {
const address = interfaces[k][k2];
if ( (address.family === 'IPv4' || address.family === 'IPv6') &&
!address.internal) {
addresses.push(address.address);
}
}
}
console.log(addresses);

Resources