【问题标题】:Express.js req.ip is returning ::ffff:127.0.0.1Express.js req.ip 正在返回 ::ffff:127.0.0.1
【发布时间】:2015-06-07 07:48:38
【问题描述】:

我目前正在尝试获取所请求用户的 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({})
});

【问题讨论】:

标签: node.js express


【解决方案1】:

::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 undecillion 应该是 对任何人来说都足够了”——比尔·盖茨谈 IPv6。

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

一些网络目前正在运行 IPv6,您很快就会遇到 IPv6 IP 地址;现在就进行飞跃,否则将来可能会破坏您的代码。

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

如果您想让您的代码与 IPv6 兼容,您所要做的就是检查 ::ffff: 前缀...如果存在,请将其删除并将其余部分作为 IPv4 处理...如果 ::ffff: 不存在'不存在,它是一个 IPv6 地址,需要这样处理。 您可以通过查看字符串中是否包含句点来仔细检查,如果是,则为 IPv4。

请记住,除了您需要对 IP 地址进行调整外,您只是在记录 IP,对吗?对于解析器和日志聚合来说,期待::ffff:127.0.0.1 等在未来很重要。除非您需要更改 IP,否则将其保留为您收到的内容。

【讨论】:

  • 不过,检查::ffff: 前缀 听起来相当危险。你知道,IPv6 有很多符号。
  • 不,这很安全 :) 有提案,然后有实施。 en.wikipedia.org/wiki/… IETF 已经认识到路由器不能花费那么多周期来寻找 IP 地址,而且在野外,没有人保留零,因为它浪费了空间。允许零的想法只是一个想法。在 2019 年,如果您在网络数据包中发送 ::ffff: 为 0000:0000:ffff:0000,虽然在技术上对原始提案有效,但对于当前的 IETF 建议无效,并且在大多数 IPv6 兼容路由器中不会出现。
  • 所以我可以确定它们总是在 canonical 形式中。不知道野外情况如何。谢谢。
  • 不幸的是,这很常见。人类只在必要时才注意。有人草拟了一些东西,最初的设计支持很多功能,他们制作了一个 RFC,没有人真正关注设计的许多部分,它成为标准,然后当实施时人们注意到需要进行重大更改 :) IPv6 有点奇怪因为称它为“规范”有点奇怪。他们可能应该将其称为“1.1”或其他名称,以便人们可以快速了解发生了什么,但由于原始草案的可选零使您在路由器上花费了 10 倍以上的计算,因此它被忽略了。
【解决方案2】:

这似乎是 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)
}

【讨论】:

    【解决方案3】:

    如果您只需要 IPv4,您可以强制节点服务器使用 IPv4 进行侦听。

    对于快速应用编辑/bin/www:

    改变

    server.listen(port);
    

    到

    server.listen(port, '0.0.0.0');
    

    这至少对我有用。

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

    【讨论】:

      【解决方案4】:

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

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

      Transition from IPv4

      【讨论】:

      • 问题提到::ffff:0:0/96,而不是::ffff:0:0:0/96
      【解决方案5】:

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

      例如

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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:
          var ip = req.ip.split(':').pop();
          

          【讨论】:

          • 正如其他答案所解释的,这是一个 IPv6 地址。请参阅上面的@Nick Steele 的回答。你真的不想这样做。
          【解决方案8】:

          您可以单独获取您的 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]);  
                }
          

          【讨论】:

          • 如果有人想知道为什么这被否决了,那是因为这个答案涉及主机/服务器 IP 地址,而不是请求的传入 IP 地址。
          猜你喜欢
          • 2014-12-21
          • 2018-12-12
          • 2018-09-22
          • 2021-01-05
          • 1970-01-01
          • 1970-01-01
          • 2013-10-19
          • 2021-03-18
          • 1970-01-01
          相关资源
          最近更新 更多