147

I am currently trying to get the IP of the requested user. The problem is the IP is returning ::ffff:127.0.0.1 instead of 127.0.0.1. I tried using trusted proxy option (though not using a proxy) and the req.ips is blank. Using 4.x Express.js.

router.get('/', function(req, res, next) {
    console.log('ip', req.ip)
    res.send({})
});
rockerBOO
  • 2,920
  • 2
  • 16
  • 22

8 Answers8

225

::ffff: is a subnet prefix for IPv4 (32 bit) addresses that are placed inside an IPv6 (128 bit) space. IPv6 is broken into two parts, the subnet prefix, and the interface suffix. Each one is 64 bits long, or, 4 groups of 4 hexadecimal characters.

In IPv6, you are allowed to remove leading zeros, and then remove consecutive zeros, meaning ::ffff: actually translates to 0000:0000:ffff:0000, this address has been designated as the IPv4 to IPv6 subnet prefix, so any IPv6 processor will understand it's working with an IPv4 address and handle it accordingly.

In the near future, IP addresses will all be IPv6, this is because we are nearly out of numbers (4.2 billion, minus some space for misc. purposes) in the IPv4 address space.

IPv6 allows for a much larger space. "340 undecillion ought to be enough for anyone" - Bill Gates speaking on IPv6.

It is important to start addressing IP addresses using the IPv6 namespace and therefore include the ::ffff: in your code because in the future there will be real hexadecimal data between those colons. If you strip it off for aesthetic reasons, your code will break when it switches to an IPv6 network or it's confronted with an IPv6 address.

Some networks are currently running IPv6 and you will soon be confronted with IPv6 IP addresses; make the leap now or risk breaking your code in the future.

The TL;DR (short) version of the matter is: Everything is working fine. Don't change it, it's the IPv6 version of an IPv4 address.

IPv4 IPv6

If you want to make your code compatible with IPv6, all you have to do is check for the ::ffff: prefix... if it exists, remove it and process the remainder as IPv4... if ::ffff: doesn't exist, it's an IPv6 address and needs to be processed as such. You can double-check by seeing if periods are in the string, if so, it's IPv4.

Keep in mind for everything but adjustments you need to make to IP addresses, you're just recording the IP, right? It's going to be important to the parser and log aggregates to expect ::ffff:127.0.0.1 and such in the future. Unless you need to alter an IP, just leave it as what you receive.

Chunky Chunk
  • 16,553
  • 15
  • 84
  • 162
Nick Steele
  • 7,419
  • 4
  • 36
  • 33
  • It sounds fairly dangerous to _check for the `::ffff:` prefix_, though. You know, an IPv6 has many notations. – Константин Ван Sep 09 '19 at 10:34
  • 2
    No it's safe :) There is the proposal, and then there is the implementation. https://en.wikipedia.org/wiki/IPv6_address#Recommended_representation_as_text The IETF has recognized that routers cannot burn that many cycles looking for IP addresses, and also in the wild, nobody keeps the zeros because it's wasted space. The idea to allow the zeros was just an idea. In 2019 if you sent ::ffff: in a network packet as 0000:0000:ffff:0000, although technically valid for the original proposal, it's invalid for the current IETF recommendation as well as wont be seen in most IPv6 compatible routers. – Nick Steele Sep 09 '19 at 20:02
  • 1
    So I can be sure about them always being in the _canonical_ forms. Didn’t know how things were going in the wild. Thanks. – Константин Ван Sep 10 '19 at 01:33
  • 2
    This is common unfortunately. Humans pay attention only when necessary. Someone drafts something, the original design supports a lot of features, they make an RFC, nobody really pays attention to many parts of the design, it becomes a standard, then when implemented people notice big changes are needed :) IPv6 is a little odd because calling it "cannonical" is a little weird. They should probably call it "1.1" or something so people can quickly understand what's going on, but because the original draft's optional zeros makes you spend 10x more compute in routers, it was simply ignored. – Nick Steele Sep 10 '19 at 16:38
45

This seems to be a quirk of ipv6: for ipv4 addresses, ipv6 seems to mix ipv6 notation with ipv4 notation.

In order to get both ipv4 and ipv6 addresses in the simple, unmixed notation, I am using:

var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
if (ip.substr(0, 7) == "::ffff:") {
  ip = ip.substr(7)
}
anneb
  • 5,510
  • 2
  • 26
  • 26
35

If you just need IPv4, you could force the node server to listen using IPv4.

For an express app edit /bin/www:

change

server.listen(port);

to

server.listen(port, '0.0.0.0');

This worked for me at least.

https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback

Your Friend Ken
  • 8,644
  • 3
  • 32
  • 41
11

Windows 7 has IPv6 enabled by default. Even though my server listens on IPv4 only, Windows 7 sends the ::ffff: prefix to the IPv4 as part of the transition to IPv6

::ffff:0:0:0/96 — A prefix used for IPv4-translated addresses which are used by the Stateless IP/ICMP Translation (SIIT) protocol.

Transition from IPv4

rockerBOO
  • 2,920
  • 2
  • 16
  • 22
10

I was having issues with the trying to compare ipv4 mapped addresses, and found the ipaddr.js library helpful :-)

eg

_.isEqual(ipaddr.process('::ffff:127.0.0.1'), ipaddr.process('127.0.0.1')) === true
Bryce
  • 391
  • 3
  • 8
10

Try this to get exact ip address by removing subnetting,

    let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    ip = ip.toString().replace('::ffff:', '');
Michael Nelles
  • 5,426
  • 8
  • 41
  • 57
-2

You can Get your Ip address alone or with The specified family using sockets

     var app = require('express')();

 app.get("/ip", (req, res) => {
        console.log(req.ip) 
       let ip = req.ip.split(':');
        let ip_details = req.socket.address();
          console.log(ip_details);                     
   // { address: '::ffff:127.0.0.1', family: 'IPv6', port: 3001 

           console.log(ip[3]);//127.0.0.1
                            res.json(ip[3]);  
      }
  • 4
    In case anyone is wondering why this has been down-voted, it's because this answer involves the host/server IP address and not the incoming IP address of the request. – tfrancois Nov 20 '21 at 19:44
-2
var ip = req.ip.split(':').pop();
Mateo Marin
  • 265
  • 3
  • 8