Express.js req.ip返回:: ffff:127.0.0.1


99

我目前正在尝试获取所请求用户的IP。问题是IP正在返回,::ffff:127.0.0.1而不是127.0.0.1。我尝试使用trusted proxy选项(尽管未使用代理),但req.ips为空。使用4.x Express.js。

router.get('/', function(req, res, next) {
    console.log('ip', req.ip)
    res.send({})
});

那么,你用req.ip还是req.ips
Aleksandr M

req.ip,只是req.ips作为测试而尝试。我只是不确定是什么引起了前缀::ffff:
rockerBOO 2015年


是的,就是这样。Windows 7具有用于IPv4请求的过渡层,并将此前缀添加到IP。
rockerBOO 2015年

Answers:


157

::ffff:是放置在IPv6(128位)空间内的IPv4(32位)地址的子网前缀。IPv6分为两部分,子网前缀和接口后缀。每个位长为64位,或者是4组的4个十六进制字符。

在IPv6中,允许您删除前导零,然后删除连续的零,即::ffff:实际上转换为0000:0000:ffff:0000,此地址已指定为IPv4到IPv6的子网前缀,因此任何IPv6处理器都可以理解它正在使用IPv4地址并进行处理。相应地。

在不久的将来,IP地址将全部为IPv6,这是因为我们在IPv4地址空间中几乎用完了数字(42亿,减去其他用途的空间)。

IPv6允许更大的空间。“ 340亿美元对任何人都应该足够”-比尔·盖茨在IPv6上发表讲话。

开始使用IPv6名称空间寻址IP地址并因此将其包含::ffff:在代码中非常重要,因为将来在这些冒号之间会出现实际的十六进制数据。如果出于审美原因将其剥离,则当代码切换到IPv6网络或遇到IPv6地址时,代码将中断。

有些网络当前正在运行IPv6,很快您将面临IPv6 IP地址;这将给您带来麻烦。立即取得飞跃,否则将来就有可能破坏您的代码。

问题的TL; DR(简短)版本是:一切正常。请勿更改,它是IPv4地址的IPv6版本。

IPv4 IPv6

如果要使代码与IPv6兼容,只需检查::ffff:前缀...是否存在,将其删除并将其余部分作为IPv4处理...如果::ffff:不存在,则为IPv6地址,需要这样处理。您可以通过查看句点是否在字符串中来进行双重检查,如果是,则为IPv4。

请记住,除了需要对IP地址进行调整以外的所有内容,您只是在记录IP,对吗?这对于解析器和日志聚合::ffff:127.0.0.1在将来的预期中非常重要。除非您需要更改IP,否则请保留其原样。


不过,检查::ffff:前缀听起来很危险。您知道,IPv6有许多符号。
КонстантинВан

1
不,这很安全:)有建议,然后有实施。en.wikipedia.org/wiki/…IETF已经认识到路由器无法消耗那么多周期来寻找IP地址,而且在野外,没人浪费零,因为这浪费了空间。允许零的想法只是一个想法。在2019年,如果您在网络数据包中以0000:0000:ffff:0000的形式发送:: ffff :,尽管在技术上对原始提案有效,但对于当前的IETF建议无效,并且在大多数IPv6兼容路由器中也不会出现。
尼克·斯蒂尔

1
因此,我可以确定它们始终处于规范形式。不知道野外情况如何。谢谢。
КонстантинВан

不幸的是,这很常见。人类仅在必要时注意。有人起草了一些东西,原始的设计支持很多功能,他们制定了RFC,没有人真正注意设计的许多部分,它成为了标准,然后当人们意识到需要进行大的更改时:) IPv6有点奇怪因为称其为“规范的”有点奇怪。他们可能应该将其称为“ 1.1”,以便人们可以快速了解发生了什么,但是由于原始草案的可选零使您在路由器上花费了10倍的计算量,因此被忽略了。
尼克·斯蒂尔

29

这似乎是ipv6的一个怪癖:对于ipv4地址,ipv6似乎将ipv6表示法与ipv4表示法混合在一起。

为了使用简单的,未混合的表示法获取ipv4和ipv6地址,我在使用:

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


10

Windows 7默认情况下启用了IPv6。即使我的服务器仅侦听IPv4,Windows 7也会将::ffff:前缀发送到IPv4,作为向IPv6过渡的一部分

::ffff:0:0:0/96 —用于无状态IP / ICMP转换(SIIT)协议使用的IPv4转换地址的前缀。

从IPv4过渡


8

我在尝试比较ipv4映射的地址时遇到问题,发现ipaddr.js库很有帮助:-)

例如

_.isEqual(ipaddr.process('::ffff:127.0.0.1'), ipaddr.process('127.0.0.1')) === true

3

尝试通过删除子网划分来获取确切的IP地址,

    let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    ip = ip.toString().replace('::ffff:', '');

-2

您可以使用套接字单独获得IP地址或与指定的家庭获得IP地址

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.