Express.js req.ip está retornando :: ffff: 127.0.0.1

98

No momento, estou tentando obter o IP do usuário solicitado. O problema é que o IP está retornando em ::ffff:127.0.0.1vez de 127.0.0.1. Tentei usar a trusted proxyopção (embora não use um proxy) e req.ipsestá em branco. Usando 4.x Express.js.

router.get('/', function(req, res, next) {
    console.log('ip', req.ip)
    res.send({})
});
rockerBOO
fonte
Então, o que você está usando req.ipou req.ips?
Aleksandr M,
req.ip, apenas tentei req.ipscomo um teste. Só não tenho certeza do que está causando o prefixo ::ffff:.
rockerBOO
Sim, era isso. O Windows 7 tem uma camada de transição para solicitações IPv4 e adiciona esse prefixo ao IP.
rockerBOO

Respostas:

155

::ffff:é um prefixo de sub-rede para endereços IPv4 (32 bits) colocados dentro de um espaço IPv6 (128 bits). O IPv6 é dividido em duas partes, o prefixo da sub-rede e o sufixo da interface. Cada um tem 64 bits ou 4 grupos de 4 caracteres hexadecimais.

No IPv6, você tem permissão para remover zeros à esquerda e, em seguida, remover zeros consecutivos, o que significa que ::ffff:na verdade se traduz em 0000:0000:ffff:0000, este endereço foi designado como o prefixo de sub-rede IPv4 para IPv6, então qualquer processador IPv6 entenderá que está trabalhando com um endereço IPv4 e o tratará adequadamente.

Em um futuro próximo, os endereços IP serão todos IPv6, isso porque estamos quase sem números (4,2 bilhões, menos algum espaço para diversos fins) no espaço de endereços IPv4.

O IPv6 permite um espaço muito maior. "340 undecilhões deveriam ser o suficiente para qualquer um" - Bill Gates falando sobre IPv6.

É importante começar a endereçar endereços IP usando o namespace IPv6 e, portanto, incluí- ::ffff:los em seu código, porque no futuro haverá dados hexadecimais reais entre esses dois pontos. Se você retirá-lo por motivos estéticos, seu código será interrompido quando for alternado para uma rede IPv6 ou confrontado com um endereço IPv6.

Algumas redes estão rodando IPv6 e você logo será confrontado com endereços IP IPv6; dê o salto agora ou arrisque quebrar seu código no futuro.

A versão TL; DR (curta) da questão é: Tudo está funcionando bem. Não mude, é a versão IPv6 de um endereço IPv4.

IPv6 IPv4

Se você deseja tornar seu código compatível com IPv6, basta verificar o ::ffff:prefixo ... se existir, remova-o e processe o restante como IPv4 ... se ::ffff:não existir, é um endereço IPv6 e precisa ser processado como tal. Você pode verificar se há pontos na string, se sim, é IPv4.

Lembre-se de tudo, exceto os ajustes que você precisa fazer nos endereços IP, você está apenas gravando o IP, certo? Será importante que o analisador e os agregados de log esperem ::ffff:127.0.0.1e tal no futuro. A menos que você precise alterar um IP, deixe-o como está sendo recebido.

Nick Steele
fonte
No entanto, parece bastante perigoso verificar o ::ffff:prefixo . Você sabe, um IPv6 tem muitas notações.
Константин Ван
1
Não, é seguro :) Existe a proposta e depois a implementação. en.wikipedia.org/wiki/… O IETF reconheceu que os roteadores não podem queimar tantos ciclos procurando por endereços IP, e também em estado selvagem, ninguém guarda os zeros porque é espaço desperdiçado. A ideia de permitir os zeros foi apenas uma ideia. Em 2019 se você enviou :: ffff: em um pacote de rede como 0000: 0000: ffff: 0000, embora tecnicamente válido para a proposta original, é inválido para a recomendação IETF atual e não será visto na maioria dos roteadores compatíveis com IPv6.
Nick Steele,
1
Portanto, posso ter certeza de que eles sempre estarão nas formas canônicas . Não sabia como as coisas estavam indo na selva. Obrigado.
Константин Ван
Isso é comum, infelizmente. Os humanos prestam atenção apenas quando necessário. Alguém desenha algo, o design original suporta muitos recursos, eles fazem um RFC, ninguém realmente presta atenção a muitas partes do design, torna-se um padrão, então quando implementado as pessoas notam que grandes mudanças são necessárias :) IPv6 é um pouco estranho porque chamá-lo de "canônico" é um pouco estranho. Eles provavelmente deveriam chamá-lo de "1.1" ou algo assim para que as pessoas possam entender rapidamente o que está acontecendo, mas como os zeros opcionais do rascunho original fazem você gastar 10 vezes mais computação em roteadores, ele foi simplesmente ignorado.
Nick Steele
29

Esta parece ser uma peculiaridade do ipv6: para endereços ipv4, ipv6 parece misturar a notação ipv6 com a notação ipv4.

Para obter os endereços ipv4 e ipv6 na notação simples e não misturada, estou usando:

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

O Windows 7 tem IPv6 habilitado por padrão. Embora meu servidor escute apenas no IPv4, o Windows 7 envia o ::ffff:prefixo para o IPv4 como parte da transição para o IPv6

::ffff:0:0:0/96 - Um prefixo usado para endereços traduzidos para IPv4 que são usados ​​pelo protocolo Stateless IP / ICMP Translation (SIIT).

Transição de IPv4

rockerBOO
fonte
8

Eu estava tendo problemas ao tentar comparar endereços mapeados ipv4 e achei a biblioteca ipaddr.js útil :-)

por exemplo

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

Tente isso para obter o endereço IP exato removendo as sub-redes,

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

Você pode obter seu endereço IP sozinho ou com a família especificada usando soquetes

     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]);  
      }
Muthukumar selvaraj
fonte
-2
var ip = req.ip.split(':').pop();
Mateo Marin
fonte
Como explicam outras respostas, este é um endereço IPv6. Veja a resposta de @Nick Steele acima. Você realmente não quer fazer isso.
Misha Nasledov