PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Déterminer le pays à partir de l'IP - IPv6

Je crois avoir trouvé la solution. Cela implique d'abord de modifier les données, puis de masser l'entrée. Voici ce qui a fonctionné.

Tout d'abord, les données doivent être converties afin que toutes les adresses soient complètes, sans raccourcissement, avec les séparateurs point-virgule supprimés. Les exemples de données affichés dans ma question sont convertis en :

 t_start                          | t_end                            | t_country_code
----------------------------------+----------------------------------+----------------
 00000000000000000000000000000000 | 00ffffffffffffffffffffffffffffff | ZZ
 01000000000000000000000000000000 | 01ffffffffffffffffffffffffffffff | ZZ
...
 20000000000000000000000000000000 | 2000ffffffffffffffffffffffffffff | ZZ
...
 20011200000000000000000000000000 | 20011200ffffffffffffffffffffffff | MX
...

C'est ce qui est stocké dans la base de données.

L'étape suivante consistait à convertir l'adresse IP reçue dans le code pour qu'elle soit dans le même format. Cela se fait en PHP avec le code suivant (supposons que $ip_address est l'adresse IPv6 entrante) :

$addr_bin = inet_pton($ip_address);                                                                                                              
$bytes = unpack('n*', $addr_bin);
$ip_address = implode('', array_map(function ($b) {return sprintf("%04x", $b); }, $bytes));

Maintenant la variable $ip_adress contiendra l'adresse IPv6 complète, par exemple

:: => 00000000000000000000000000000000
2001:1200::ab => 200112000000000000000000000000ab

et ainsi de suite.

Maintenant, vous pouvez simplement comparer cette adresse complète avec les plages de la base de données. J'ai ajouté une deuxième fonction à la base de données pour gérer les adresses IPv6, qui ressemble à ceci :

CREATE OR REPLACE FUNCTION get_country_for_ipv6(character varying)
  RETURNS character varying AS
$BODY$
declare
    ip  ALIAS for $1;
    ccode   varchar;
begin
    select into ccode t_country_code from ipv6_to_country where addr between n_from and n_to limit 1;
    if ccode is null then
        ccode := '';
    end if;
    return ccode;
end;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

Enfin, dans mon code php, j'ai ajouté le code qui appelle l'une ou l'autre fonction Postgres en fonction de l'entrée ip_address.